package com.ctshk.rpc.order.tour.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ctshk.common.constant.ElasticSearchConstant;
import com.ctshk.common.dto.payment.CallPayDTO;
import com.ctshk.common.elasticsearch.config.ElasticSearchConfiguration;
import com.ctshk.common.enums.*;
import com.ctshk.common.enums.Currency;
import com.ctshk.common.enums.payment.PayCurrency;
import com.ctshk.common.model.AppReq;
import com.ctshk.common.req.pay.NotifyConsumeReq;
import com.ctshk.common.utils.*;
import com.ctshk.rpc.finance.req.bill.BillAddCollectionReq;
import com.ctshk.rpc.finance.service.IFinanceBillService;
import com.ctshk.rpc.order.tour.code.*;
import com.ctshk.rpc.order.tour.code.CollectionTypeIdCode;
import com.ctshk.rpc.order.tour.code.IsDeletedCode;
import com.ctshk.rpc.order.tour.dto.*;
import com.ctshk.rpc.order.tour.dto.client.*;
import com.ctshk.rpc.order.tour.dto.custom.CustomOrderUpdateContactDTO;
import com.ctshk.rpc.order.tour.entity.*;
import com.ctshk.rpc.order.tour.enums.IsPayStatusCode;
import com.ctshk.rpc.order.tour.enums.TourOrderStatusCode;
import com.ctshk.rpc.order.tour.enums.TourRefundStatusCode;
import com.ctshk.rpc.order.tour.mapper.*;
import com.ctshk.rpc.order.tour.req.*;
import com.ctshk.rpc.order.tour.req.client.*;
import com.ctshk.rpc.order.tour.req.custom.CustomOrderUpdateContactReq;
import com.ctshk.rpc.order.tour.task.SmsTask;
import com.ctshk.rpc.order.tour.vo.TouristCollectionFeeJson;
import com.ctshk.rpc.payment.enums.PayOrderStatus;
import com.ctshk.rpc.payment.enums.PaymentMethod;
import com.ctshk.rpc.payment.service.IPayService;
import com.ctshk.rpc.starvip.dto.start_vip.user.Contact;
import com.ctshk.rpc.starvip.dto.start_vip.user.LoyMember;
import com.ctshk.rpc.starvip.req.TransactionIntegralCommonReq;
import com.ctshk.rpc.starvip.req.user.UserInfoQueryReq;
import com.ctshk.rpc.starvip.service.IStarVipBusinessService;
import com.ctshk.rpc.starvip.service.IStarVipUserService;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.dto.MainDataRowFieldDataDTO;
import com.ctshk.rpc.system.dto.mian.data.MainDataDeductionRulesDTO;
import com.ctshk.rpc.system.dto.mian.data.MainDataDeductionRulesDetailsDTO;
import com.ctshk.rpc.system.req.DispatchOrderRuleGetUserReq;
import com.ctshk.rpc.system.req.MainDataCurrencyUpdateStatusReq;
import com.ctshk.rpc.system.req.main.data.MainDataDeductionRulesIdReq;
import com.ctshk.rpc.system.service.*;
import com.ctshk.rpc.tour.dto.cache.*;
import com.ctshk.rpc.tour.req.*;
import com.ctshk.rpc.tour.req.es.TripCacheUpdateReq;
import com.ctshk.rpc.tour.service.ISeriesTripAppService;
import com.ctshk.rpc.tour.service.ISeriesTripService;
import com.ctshk.rpc.user.dto.AppUserDTO;
import com.ctshk.rpc.user.service.IOrderEsService;
import com.ctshk.rpc.user.service.IUserService;
import com.ctshk.rpc.user.service.IUserSmsService;
import com.github.kfcfans.powerjob.client.OhMyClient;
import com.github.kfcfans.powerjob.common.response.ResultDTO;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.service.support.BaseService;
import com.ctshk.rpc.iotc.service.IOperatePromotionService;
import com.ctshk.rpc.order.tour.constant.Constants;
import com.ctshk.rpc.order.tour.service.ISeriesOrderService;
import com.ctshk.rpc.order.tour.service.ISeriesOrderTouristFeeAdjustService;
import com.ctshk.rpc.order.tour.service.ISeriesOrderTouristInfoService;
import com.ctshk.rpc.order.tour.service.ISeriesOrderTouristOtherFeeService;
import com.ctshk.rpc.order.tour.util.Utils;
import com.ctshk.rpc.system.dto.SysDepartmentDTO;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.dto.member.ContactQueryDTO;
import com.ctshk.rpc.system.dto.member.CrmAccountDTO;
import com.ctshk.rpc.system.req.crm.member.CrmMemberQueryReq;
import com.ctshk.rpc.tour.dto.schedule.SeriesTripScheduleDTO;
import com.ctshk.rpc.tour.dto.schedule.SeriesTripScheduleDataDTO;
import com.ctshk.rpc.tour.dto.schedule.SeriesTripScheduleDefaultCostCollectionDTO;
import com.ctshk.rpc.tour.dto.schedule.SeriesTripScheduleDefaultCostTouristTypeDTO;
import com.ctshk.rpc.tour.dto.schedule.SeriesTripScheduleDefaultFeeAdjustDTO;
import com.ctshk.rpc.tour.dto.schedule.SeriesTripScheduleSellingPriceDTO;
import com.ctshk.rpc.tour.dto.schedule.SeriesTripScheduleTeamRuleDTO;
import com.ctshk.rpc.tour.dto.schedule.TripScheduleDefaultCostDTO;
import com.ctshk.rpc.tour.dto.schedule.TripScheduleListDTO;
import com.ctshk.rpc.tour.req.schedule.TripScheduleListIdReq;
import com.ctshk.rpc.tour.req.schedule.UpdateScheduleNumReq;
import com.ctshk.rpc.tour.req.schedule.UpdateSchedulePassengerReq;
import com.ctshk.rpc.tour.service.ISeriesTripScheduleService;
import com.ctshk.rpc.workflow.dto.ApprovalCheckDTO;
import com.ctshk.rpc.workflow.dto.ApprovalStartDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;

import lombok.extern.slf4j.Slf4j;

import static com.ctshk.rpc.order.tour.constants.TourConstants.CUSTOM_URI;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;

/**
 * <p>
 * 系列团订单 服务实现类
 * </p>
 *
 * @author 谭响
 * @since 2021-01-18
 */
@Slf4j
@DubboService
public class SeriesOrderServiceImpl extends ServiceImpl<SeriesOrderMapper, SeriesOrder> implements ISeriesOrderService, BaseService {

    @Autowired
    private SeriesOrderMapper seriesOrderMapper;
    @Autowired
    private SeriesOrderTouristQuitMapper seriesOrderTouristQuitMapper;
    @Autowired
    private SeriesOrderTouristInfoMapper seriesOrderTouristInfoMapper;

    @Autowired
    private ISeriesOrderTouristInfoService iSeriesOrderTouristInfoService;

    @Autowired
    private SeriesOrderAmountStatisticsMapper seriesOrderAmountStatisticsMapper;

    @Autowired
    private SeriesOrderCollectionMapper seriesOrderCollectionMapper;

    @DubboReference
    private ISeriesTripScheduleService iSeriesTripScheduleService;

    @DubboReference
    private ISeriesTripService seriesTripService;

    @DubboReference
    private IFinanceBillService iFinanceBillService;

    @Autowired
    private ISeriesOrderTouristOtherFeeService iSeriesOrderTouristOtherFeeService;

    @DubboReference
    private IMainDataTouristTypeService iMainDataTouristTypeService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private RedisTemplate<String, String> redis;

    @Autowired
    private ISeriesOrderTouristFeeAdjustService iSeriesOrderTouristFeeAdjustService;

    @DubboReference
    private IMainDataCurrencyService iMainDataCurrencyService;

    @DubboReference
    private ISysUserService iSysUserService;

    @DubboReference
    private IOperatePromotionService iOperatePromotionService;

    @DubboReference
    private ICrmMemberService iCrmMemberService;

    @DubboReference
    private ISysApprovalService iSysApprovalService;

    @DubboReference
    private ISysPermissionService iSysPermissionService;

    @DubboReference
    private ISysDepartmentService iSysDepartmentService;

    @DubboReference
    private IMainDataDeductionRulesService deductionRulesService;

    @Autowired
    private SeriesOrderReceiptMapper seriesOrderReceiptMapper;

    @Autowired
    private SeriesOrderTouristVisaMapper seriesOrderTouristVisaMapper;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @DubboReference
    private IPayService iPayService;

    @DubboReference
    private IUserSmsService userSmsService;

    @DubboReference
    private IDispatchOrderRuleService dispatchOrderRuleService;

    @DubboReference
    private IMainDataAreaNumberService iMainDataAreaNumberService;

    @DubboReference
    private ISysUserService sysUserService;

    @DubboReference
    private ISeriesTripAppService seriesTripAppService;

    @DubboReference
    private IStarVipUserService starVipUserService;

    @DubboReference
    private IUserService iUserService;

    @DubboReference
    private IStarVipBusinessService iStarVipBusinessService;

    @DubboReference
    private IOrderEsService orderEsService;

    @DubboReference
    private IMainDataTableService iMainDataTableService;

    @Value("${schedule.config.domain}")
    private String domain;

    @Value("${schedule.config.app-name}")
    private String appName;

    @Value("${schedule.config.password}")
    private String password;

    @Value("${schedule.job-id.close-occupy}")
    private long jobIdCloseOccupy;

    @Value("${schedule.job-id.close-keep}")
    private long jobIdCloseKeep;

    @Value("${schedule.job-id.order.tour}")
    private long jobId;

    /**
     * 添加
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<SeriesOrderDTO> down(SeriesOrderDownReq req, TokenUser tokenUser) {

        //获取团期，判断是否能下单
//        SeriesTripScheduleDTO tripScheduleDTO = iSeriesTripScheduleService.getTripScheduleId(req.getScheduleId());

        /*FindTripScheduleReq findTripScheduleReq = new FindTripScheduleReq();
        findTripScheduleReq.setAgentId(req.getAgentId());
        findTripScheduleReq.setId(req.getScheduleId());
        if (req.getOrderType() == 0) {
            findTripScheduleReq.setType(1);
        }
        if (req.getOrderType() == 2) {
            findTripScheduleReq.setType(2);
        }*/
        SeriesTripScheduleDTO tripScheduleDTO = iSeriesTripScheduleService.getTripScheduleId(req.getScheduleId());
//        System.out.println("自营价格++++++++++："+ tripScheduleDTO.getTripScheduleDefaultCost().getSeriesTripScheduleSellingPriceDTO().getGroupCustomerPrice());

        SeriesTripScheduleDataDTO seriesTripScheduleDataDTO = tripScheduleDTO.getSeriesTripScheduleDataDTO();
        SeriesTripScheduleTeamRuleDTO seriesTripScheduleTeamRuleDTO = tripScheduleDTO.getSeriesTripScheduleTeamRuleDTO();

        if (seriesTripScheduleTeamRuleDTO.getMaxPeople() - seriesTripScheduleDataDTO.getLockedTouristNum() <= 0) {
            return Result.failed(SeriesOrderErrorCode.PEOPLE_LIMIT);
        }
        Integer nightDays = seriesTripScheduleDataDTO.getNightDays();
        if (org.springframework.util.StringUtils.isEmpty(nightDays)) {
            return Result.failed(SeriesOrderErrorCode.NIGHT_DAY_IS_NULL);
        }
        Integer totalPeople = 0;
        //检查游客类型
        BitSet bitSet = new BitSet();
        List<Passenger> passengerList = seriesTripScheduleTeamRuleDTO.getPassenger();
        int touristTypeSize = 0;
        for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
            totalPeople += touristReq.getPeople();
            for (Passenger passenger : passengerList) {
                if (Objects.equals(touristReq.getTouristTypeId(), passenger.getId())) {
                    bitSet.set(touristTypeSize);
                    break;
                }
            }
            touristTypeSize++;
        }
        if (touristTypeSize == bitSet.cardinality()) {
            return Result.failed(SeriesOrderErrorCode.DOWN_ORDER_TOURIST_LIMIT);
        }

        //更新团期 余位
        UpdateSchedulePassengerReq updateSchedulePassengerReq = new UpdateSchedulePassengerReq();
        updateSchedulePassengerReq.setId(req.getScheduleId());
        updateSchedulePassengerReq.setType(UpdateSchedulePassengerTypeCode.DOWN.getCode());
        updateSchedulePassengerReq.setLockedTouristNum(totalPeople);
        Result result = iSeriesTripScheduleService.updateSchedulePassengerReq(updateSchedulePassengerReq, tokenUser);
        if (!result.isSuccess()) {
            return result;
        }

        //占床数
        int occupyBedNum = 0;
        //不占床数
        int notOccupyBedNum = 0;
        for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
            //单房差
            for (Passenger passenger : seriesTripScheduleTeamRuleDTO.getPassenger()) {
                if (Objects.equals(passenger.getMainDataId(), touristReq.getTouristTypeId())) {
                    if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.YES.getCode())) {
                        occupyBedNum = occupyBedNum + touristReq.getPeople();
                    } else if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.NO.getCode())) {
                        notOccupyBedNum = notOccupyBedNum + touristReq.getPeople();
                    }
                }
            }
        }
        Integer rooms = 0;
        Integer singleRoomNum = 0;
        //计算最终所需房间数
        if (req.getRoomNum() > 0) {
            //计算最终所需房间数
            Map<String, Integer> roomsResult = SingleRoomUtil.computeRooms(occupyBedNum, notOccupyBedNum,
                    req.getRoomNum(),
                    (double) seriesTripScheduleTeamRuleDTO.getOccupyBedNum(),
                    (double) seriesTripScheduleTeamRuleDTO.getNotOccupyBedNum());
            rooms = roomsResult.get("rooms");
            singleRoomNum = roomsResult.get("singleRoomNum");
        }
        long orderId = SnowflakeIdWorker.nextId();
        LocalDateTime now = LocalDateTime.now();
        SeriesOrder seriesOrder = EntityUtil.copy(req, SeriesOrder.class);

        List<SeriesOrderTouristInfoSaveBatchReq> touristInfoSaveBatchReqList = new ArrayList<>();
        List<SeriesOrderTouristOtherFeeSaveBatchReq> otherFeeSaveBatchReqList = new ArrayList<>();
        List<SeriesOrderTouristFeeAdjustSaveBatchReq> adjustSaveBatchReqList = new ArrayList<>();

        //团费
        BigDecimal orderGroupFee = new BigDecimal(0);
        //应收
        BigDecimal orderTotalReceivables = new BigDecimal(0);
        //实收
        BigDecimal orderTotalPaidIn = new BigDecimal(0);
        //已退款
        BigDecimal orderRefundAmount = new BigDecimal(0);
        //代收费用
        BigDecimal orderCollectionFee = new BigDecimal(0);
        //调整费用
        BigDecimal orderAdjustmentCost = new BigDecimal(0);
        //其他金额
        BigDecimal orderOtherAmount = new BigDecimal(0);
        //已出单据金额
        BigDecimal orderReceiptedAmount = new BigDecimal(0);
        //未收
        BigDecimal orderRemainingReceivables = new BigDecimal(0);
        //人数
        totalPeople = 0;
        if (Objects.equals(tripScheduleDTO.getCostSharingType(), CostSharingType.DEFAULT.getCode())) {
            //默认模板
            TripScheduleDefaultCostDTO tripScheduleDefaultCostDTO = tripScheduleDTO.getTripScheduleDefaultCost();
            SeriesTripScheduleSellingPriceDTO seriesTripScheduleSellingPriceDTO = tripScheduleDefaultCostDTO.getSeriesTripScheduleSellingPriceDTO();
            List<SeriesTripScheduleDefaultCostCollectionDTO> costCollectionList = tripScheduleDefaultCostDTO.getCostCollectionList();
            List<SeriesTripScheduleDefaultFeeAdjustDTO> feeAdjustList = tripScheduleDefaultCostDTO.getFeeAdjustList();

            //单房差
            SeriesTripScheduleDefaultFeeAdjustDTO singleRoomAdjustDTO = null;
            if (CollectionUtils.isNotEmpty(feeAdjustList) && nightDays > 0) {
                for (SeriesTripScheduleDefaultFeeAdjustDTO seriesTripScheduleDefaultFeeAdjustDTO : feeAdjustList) {
                    if (Objects.equals(seriesTripScheduleDefaultFeeAdjustDTO.getMainDataId(), Constants.SINGLE_ROOM_ID)) {
                        singleRoomAdjustDTO = seriesTripScheduleDefaultFeeAdjustDTO;
                        break;
                    }
                }
            }

            for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
                for (int i = 0; i < touristReq.getPeople(); i++) {
                    long touristId = IdWorker.getId();
                    List<TouristCollectionFeeJson> collectionFeeJsonList = new ArrayList<>();
                    SeriesOrderTouristInfoSaveBatchReq touristInfoSaveBatchReq = new SeriesOrderTouristInfoSaveBatchReq();
                    //团费
                    BigDecimal groupFee = seriesTripScheduleSellingPriceDTO.getGroupCustomerPrice();
                    //获取加幅后的团费
                    //下单类型（0 直客下单，1 代理商下单）
                    if (Objects.equals(req.getOrderType(), 0)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getUserId());
                    } else if (Objects.equals(req.getOrderType(), 1)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getAgentId());
                    }
                    //应收
                    BigDecimal totalReceivables = new BigDecimal(0);
                    //实收
                    BigDecimal totalPaidIn = new BigDecimal(0);
                    //已退款
                    BigDecimal refundAmount = new BigDecimal(0);
                    //代收费用
                    BigDecimal collectionFee = new BigDecimal(0);
                    //调整费用
                    BigDecimal adjustmentCost = new BigDecimal(0);
                    //其他金额
                    BigDecimal otherAmount = new BigDecimal(0);
                    //已出单据金额
                    BigDecimal receiptedAmount = new BigDecimal(0);
                    //未收
                    BigDecimal remainingReceivables = new BigDecimal(0);

                    if (CollectionUtils.isNotEmpty(costCollectionList)) {
                        for (SeriesTripScheduleDefaultCostCollectionDTO seriesTripScheduleDefaultCostCollectionDTO : costCollectionList) {
                            SeriesTripScheduleDefaultCostTouristTypeDTO selectTypeDTO = null;

                            //判断代收费用中是否有相同游客类型的代收费用
                            for (SeriesTripScheduleDefaultCostTouristTypeDTO typeDTO : seriesTripScheduleDefaultCostCollectionDTO.getCostCollectionTypeList()) {
                                if (Objects.equals(typeDTO.getTouristTypeId(), touristReq.getTouristTypeId())) {
                                    selectTypeDTO = typeDTO;
                                    break;
                                }
                            }

                            if (selectTypeDTO == null) {
                                continue;
                            }

                            TouristCollectionFeeJson collectionFeeJson = new TouristCollectionFeeJson();
                            collectionFeeJson.setProjectName(seriesTripScheduleDefaultCostCollectionDTO.getProjectName());
                            collectionFeeJson.setMainDataId(seriesTripScheduleDefaultCostCollectionDTO.getMainDataId());
                            collectionFeeJson.setAdjustType(1);
                            collectionFeeJson.setTotalAmount(selectTypeDTO.getTotalAmount().multiply(new BigDecimal(seriesTripScheduleDefaultCostCollectionDTO.getExchangeRate())).setScale(2, BigDecimal.ROUND_HALF_UP));
                            collectionFeeJsonList.add(collectionFeeJson);

                            //累计代收费用
                            collectionFee = collectionFee.add(selectTypeDTO.getTotalAmount());
                        }

                    }

                    if (collectionFeeJsonList.size() > 0) {
                        touristInfoSaveBatchReq.setCollectionFeeJson(JSON.toJSONString(collectionFeeJsonList));
                    }

                    //其他费用


                    //调整费用 行程晚数不为0才计算调整费用
                    if (singleRoomAdjustDTO != null && singleRoomNum > 0 && req.getRoomNum() > 0) {
                        SeriesOrderTouristFeeAdjustSaveBatchReq seriesOrderTouristFeeAdjust = new SeriesOrderTouristFeeAdjustSaveBatchReq();
                        seriesOrderTouristFeeAdjust.setRelationId(singleRoomAdjustDTO.getId());
                        BigDecimal costAmount = Assist.setScale(singleRoomAdjustDTO.getCostAmount().multiply(new BigDecimal(singleRoomAdjustDTO.getExchangeRate())));
                        seriesOrderTouristFeeAdjust.setAmount(costAmount);
                        seriesOrderTouristFeeAdjust.setPlusType(singleRoomAdjustDTO.getAdjustType());
                        seriesOrderTouristFeeAdjust.setName(singleRoomAdjustDTO.getProjectName());
                        seriesOrderTouristFeeAdjust.setTouristId(touristId);
                        seriesOrderTouristFeeAdjust.setAdjustType(AdjustTypeCode.ADJUST.getCode());
                        seriesOrderTouristFeeAdjust.setOrderId(orderId);
                        seriesOrderTouristFeeAdjust.setUserId(req.getUserId());
                        adjustSaveBatchReqList.add(seriesOrderTouristFeeAdjust);

                        singleRoomNum--;

                        //累计调整费用
                        if (Objects.equals(singleRoomAdjustDTO.getAdjustType(), PlusTypeCode.PLUS.getCode())) {
                            adjustmentCost = adjustmentCost.add(costAmount);
                        } else if (Objects.equals(singleRoomAdjustDTO.getAdjustType(), PlusTypeCode.SUBTRACT.getCode())) {
                            adjustmentCost = adjustmentCost.subtract(costAmount);
                        }
                    }

                    //应收=团费+代收+调整+其他
                    totalReceivables = ((groupFee.add(collectionFee)).add(adjustmentCost)).add(otherAmount);
                    //未收=应收-实收
                    remainingReceivables = totalReceivables.subtract(totalPaidIn);

                    touristInfoSaveBatchReq.setId(touristId);
                    touristInfoSaveBatchReq.setOrderId(orderId);
                    touristInfoSaveBatchReq.setScheduleId(seriesOrder.getScheduleId());
                    touristInfoSaveBatchReq.setMainDataId(touristReq.getTouristTypeId());
                    touristInfoSaveBatchReq.setTouristTypeName(touristReq.getTouristTypeName());
                    touristInfoSaveBatchReq.setPayStatus(PayStatusCode.WAIT.getCode());
                    touristInfoSaveBatchReq.setNoshow(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setLockStatus(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                    touristInfoSaveBatchReq.setGmtCreate(now);
                    touristInfoSaveBatchReq.setGmtModified(now);
                    touristInfoSaveBatchReq.setCreateId(req.getUserId());
                    touristInfoSaveBatchReq.setModifiedId(req.getUserId());
                    touristInfoSaveBatchReq.setIsFullInfo(ISCode.NO.getCode());
                    //订单统计
                    touristInfoSaveBatchReq.setGroupFee(groupFee);
                    touristInfoSaveBatchReq.setTotalReceivables(totalReceivables);
                    touristInfoSaveBatchReq.setTotalPaidIn(totalPaidIn);
                    touristInfoSaveBatchReq.setRefundAmount(refundAmount);
                    touristInfoSaveBatchReq.setCollectionFee(collectionFee);
                    touristInfoSaveBatchReq.setAdjustmentCost(adjustmentCost);
                    touristInfoSaveBatchReq.setOtherAmount(otherAmount);
                    touristInfoSaveBatchReq.setReceiptedAmount(receiptedAmount);
                    touristInfoSaveBatchReq.setRemainingReceivables(remainingReceivables);
                    touristInfoSaveBatchReq.setIsReceiptCalculated(ISCode.NO.getCode());
                    touristInfoSaveBatchReq.setBuyInsurance(ISCode.NO.getCode());
                    touristInfoSaveBatchReqList.add(touristInfoSaveBatchReq);

                    //人数
                    totalPeople++;
                    //团费
                    orderGroupFee = orderGroupFee.add(groupFee);
                    //应收
                    orderTotalReceivables = orderTotalReceivables.add(totalReceivables);
                    //实收
                    orderTotalPaidIn = orderTotalPaidIn.add(totalPaidIn);
                    //已退款
                    orderRefundAmount = orderRefundAmount.add(refundAmount);
                    //代收费用
                    orderCollectionFee = orderCollectionFee.add(collectionFee);
                    //调整费用
                    orderAdjustmentCost = orderAdjustmentCost.add(adjustmentCost);
                    //其他金额
                    orderOtherAmount = orderOtherAmount.add(otherAmount);
                    //已出单据金额
                    orderReceiptedAmount = orderReceiptedAmount.add(receiptedAmount);
                    //未收
                    orderRemainingReceivables = orderRemainingReceivables.add(remainingReceivables);
                }
            }

        } else if (Objects.equals(tripScheduleDTO.getCostSharingType(), CostSharingType.CUSTOM.getCode())) {
            //自定义
            TripCustomCostReq tripCustomCostReq = tripScheduleDTO.getTripCustomCostReq();
            List<TripCustomSalePriceReq> customSalePriceList = tripCustomCostReq.getCustomSalePriceList();
            ;
            List<SeriesTripDefaultCostCollectionReq> customCostCollectionList = tripCustomCostReq.getCostCollectionList();
            List<SeriesTripCustomFeeAdjustReq> customFeeAdjustList = tripCustomCostReq.getFeeAdjustList();

            for (SeriesOrderTouristReq touristReq : req.getTouristList()) {

                //团费
                TripCustomSalePriceReq selectTripCustomSalePriceReq = null;
                A:
                if (CollectionUtils.isNotEmpty(customSalePriceList)) {
                    for (TripCustomSalePriceReq tripCustomSalePriceReq : customSalePriceList) {
                        System.out.println("自定义：自营价格++++++++++：" + tripCustomSalePriceReq.getGroupCustomerPrice());
                        if (Objects.equals(tripCustomSalePriceReq.getMainDataId(), touristReq.getTouristTypeId())) {
                            if (Objects.equals(tripCustomSalePriceReq.getDateType(), DataType.WEEK.getCode())) {
                                for (Integer checkWeekDay : tripCustomSalePriceReq.getCheckWeekDays()) {
                                    if (Objects.equals(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue(), checkWeekDay)) {
                                        selectTripCustomSalePriceReq = tripCustomSalePriceReq;
                                        break A;
                                    }
                                }
                            } else if (Objects.equals(tripCustomSalePriceReq.getDateType(), DataType.DATE.getCode())) {
                                if (tripScheduleDTO.getDepartureDate().compareTo(tripCustomSalePriceReq.getDateBegin()) >= 0
                                        && tripScheduleDTO.getDepartureDate().compareTo(tripCustomSalePriceReq.getDateEnd()) <= 0) {
                                    selectTripCustomSalePriceReq = tripCustomSalePriceReq;
                                    break A;
                                }
                            }
                        }
                    }
                }

                if (selectTripCustomSalePriceReq == null) {
                    throw new BusinessException(SystemError.SYS_411);
                }

                //单房差
                SeriesTripCustomFeeAdjustReq singleRoomCustomFeeAdjustReq = null;
                CustomCostReq singleRoomCustomCostReq = null;
                if (nightDays > 0) {
                    B:
                    if (CollectionUtils.isNotEmpty(customFeeAdjustList)) {
                        for (SeriesTripCustomFeeAdjustReq seriesTripCustomFeeAdjustReq : customFeeAdjustList) {
                            if (Objects.equals(seriesTripCustomFeeAdjustReq.getMainDataId(), Constants.SINGLE_ROOM_ID)) {
                                for (CustomCostReq customCostReq : seriesTripCustomFeeAdjustReq.getCustomCostList()) {
                                    if (Objects.equals(customCostReq.getMainDataId(), touristReq.getTouristTypeId())) {
                                        if (Objects.equals(customCostReq.getDateType(), DataType.WEEK.getCode())) {
                                            for (Integer checkWeekDay : customCostReq.getCheckWeekDays()) {
                                                if (Objects.equals(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue(), checkWeekDay)) {
                                                    singleRoomCustomFeeAdjustReq = seriesTripCustomFeeAdjustReq;
                                                    singleRoomCustomCostReq = customCostReq;
                                                    break B;
                                                }
                                            }
                                        } else if (Objects.equals(customCostReq.getDateType(), DataType.DATE.getCode())) {
                                            if (tripScheduleDTO.getDepartureDate().compareTo(customCostReq.getDateBegin()) >= 0
                                                    && tripScheduleDTO.getDepartureDate().compareTo(customCostReq.getDateEnd()) <= 0) {
                                                singleRoomCustomFeeAdjustReq = seriesTripCustomFeeAdjustReq;
                                                singleRoomCustomCostReq = customCostReq;
                                                break B;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                for (int i = 0; i < touristReq.getPeople(); i++) {
                    long touristId = IdWorker.getId();
                    List<TouristCollectionFeeJson> collectionFeeJsonList = new ArrayList<>();
                    SeriesOrderTouristInfoSaveBatchReq touristInfoSaveBatchReq = new SeriesOrderTouristInfoSaveBatchReq();

                    //团费
                    BigDecimal groupFee = selectTripCustomSalePriceReq.getGroupCustomerPrice();
                    //获取加幅后的团费
                    //下单类型（0 直客下单，1 代理商下单）
                    if (Objects.equals(req.getOrderType(), 0)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getUserId());
                    } else if (Objects.equals(req.getOrderType(), 1)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getAgentId());
                    }
                    //应收
                    BigDecimal totalReceivables = new BigDecimal(0);
                    //实收
                    BigDecimal totalPaidIn = new BigDecimal(0);
                    //已退款
                    BigDecimal refundAmount = new BigDecimal(0);
                    //代收费用
                    BigDecimal collectionFee = new BigDecimal(0);
                    //调整费用
                    BigDecimal adjustmentCost = new BigDecimal(0);
                    //其他金额
                    BigDecimal otherAmount = new BigDecimal(0);
                    //已出单据金额
                    BigDecimal receiptedAmount = new BigDecimal(0);
                    //未收
                    BigDecimal remainingReceivables = new BigDecimal(0);

                    if (CollectionUtils.isNotEmpty(customCostCollectionList)) {
                        for (SeriesTripDefaultCostCollectionReq seriesTripDefaultCostCollectionReq : customCostCollectionList) {
                            SeriesTripDefaultCostCollectionTypeReq selectTypeDTO = null;

                            //判断代收费用中是否有相同游客类型的代收费用
                            for (SeriesTripDefaultCostCollectionTypeReq typeDTO : seriesTripDefaultCostCollectionReq.getCostCollectionTypeList()) {
                                if (Objects.equals(typeDTO.getTouristTypeId(), touristReq.getTouristTypeId())) {
                                    selectTypeDTO = typeDTO;
                                    break;
                                }
                            }

                            if (selectTypeDTO == null) {
                                continue;
                            }

                            TouristCollectionFeeJson collectionFeeJson = new TouristCollectionFeeJson();
                            collectionFeeJson.setProjectName(seriesTripDefaultCostCollectionReq.getProjectName());
                            collectionFeeJson.setMainDataId(seriesTripDefaultCostCollectionReq.getMainDataId());
                            collectionFeeJson.setAdjustType(1);
                            collectionFeeJson.setTotalAmount(selectTypeDTO.getTotalAmount().multiply(new BigDecimal(seriesTripDefaultCostCollectionReq.getExchangeRate())).setScale(2, BigDecimal.ROUND_HALF_UP));
                            collectionFeeJsonList.add(collectionFeeJson);

                            //累计代收费用
                            collectionFee = collectionFee.add(selectTypeDTO.getTotalAmount());
                        }

                    }

                    if (collectionFeeJsonList.size() > 0) {
                        touristInfoSaveBatchReq.setCollectionFeeJson(JSON.toJSONString(collectionFeeJsonList));
                    }

                    //其他费用


                    //调整费用
                    if (singleRoomCustomFeeAdjustReq != null && singleRoomCustomCostReq != null &&
                            singleRoomNum > 0 && nightDays > 0) {
                        SeriesOrderTouristFeeAdjustSaveBatchReq seriesOrderTouristFeeAdjust = new SeriesOrderTouristFeeAdjustSaveBatchReq();
                        seriesOrderTouristFeeAdjust.setRelationId(singleRoomCustomFeeAdjustReq.getId());
                        BigDecimal price = Assist.setScale(singleRoomCustomCostReq.getPrice().multiply(new BigDecimal(singleRoomCustomFeeAdjustReq.getExchangeRate())));
                        seriesOrderTouristFeeAdjust.setAmount(price);
                        seriesOrderTouristFeeAdjust.setPlusType(singleRoomCustomFeeAdjustReq.getAdjustType());
                        seriesOrderTouristFeeAdjust.setName(singleRoomCustomFeeAdjustReq.getProjectName());
                        seriesOrderTouristFeeAdjust.setTouristId(touristId);
                        seriesOrderTouristFeeAdjust.setAdjustType(AdjustTypeCode.ADJUST.getCode());
                        seriesOrderTouristFeeAdjust.setOrderId(orderId);
                        seriesOrderTouristFeeAdjust.setUserId(req.getUserId());
                        adjustSaveBatchReqList.add(seriesOrderTouristFeeAdjust);

                        singleRoomNum--;

                        //累计调整费用
                        if (Objects.equals(singleRoomCustomFeeAdjustReq.getAdjustType(), PlusTypeCode.PLUS.getCode())) {
                            adjustmentCost = adjustmentCost.add(price);
                        } else if (Objects.equals(singleRoomCustomFeeAdjustReq.getAdjustType(), PlusTypeCode.SUBTRACT.getCode())) {
                            adjustmentCost = adjustmentCost.subtract(price);
                        }
                    }

                    //应收=团费+代收+调整+其他
                    totalReceivables = ((groupFee.add(collectionFee)).add(adjustmentCost)).add(otherAmount);
                    //未收=应收-实收
                    remainingReceivables = totalReceivables.subtract(totalPaidIn);

                    touristInfoSaveBatchReq.setId(touristId);
                    touristInfoSaveBatchReq.setOrderId(orderId);
                    touristInfoSaveBatchReq.setScheduleId(seriesOrder.getScheduleId());
                    touristInfoSaveBatchReq.setMainDataId(touristReq.getTouristTypeId());
                    touristInfoSaveBatchReq.setTouristTypeName(touristReq.getTouristTypeName());
                    touristInfoSaveBatchReq.setPayStatus(PayStatusCode.WAIT.getCode());
                    touristInfoSaveBatchReq.setNoshow(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setLockStatus(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                    touristInfoSaveBatchReq.setGmtCreate(now);
                    touristInfoSaveBatchReq.setGmtModified(now);
                    touristInfoSaveBatchReq.setCreateId(req.getUserId());
                    touristInfoSaveBatchReq.setModifiedId(req.getUserId());
                    touristInfoSaveBatchReq.setIsFullInfo(ISCode.NO.getCode());
                    //订单统计
                    touristInfoSaveBatchReq.setGroupFee(groupFee);
                    touristInfoSaveBatchReq.setTotalReceivables(totalReceivables);
                    touristInfoSaveBatchReq.setTotalPaidIn(totalPaidIn);
                    touristInfoSaveBatchReq.setRefundAmount(refundAmount);
                    touristInfoSaveBatchReq.setCollectionFee(collectionFee);
                    touristInfoSaveBatchReq.setAdjustmentCost(adjustmentCost);
                    touristInfoSaveBatchReq.setOtherAmount(otherAmount);
                    touristInfoSaveBatchReq.setReceiptedAmount(receiptedAmount);
                    touristInfoSaveBatchReq.setRemainingReceivables(remainingReceivables);
                    touristInfoSaveBatchReq.setIsReceiptCalculated(ISCode.NO.getCode());
                    touristInfoSaveBatchReq.setBuyInsurance(ISCode.NO.getCode());
                    touristInfoSaveBatchReqList.add(touristInfoSaveBatchReq);

                    //人数
                    totalPeople++;
                    //团费
                    orderGroupFee = orderGroupFee.add(groupFee);
                    //应收
                    orderTotalReceivables = orderTotalReceivables.add(totalReceivables);
                    //实收
                    orderTotalPaidIn = orderTotalPaidIn.add(totalPaidIn);
                    //已退款
                    orderRefundAmount = orderRefundAmount.add(refundAmount);
                    //代收费用
                    orderCollectionFee = orderCollectionFee.add(collectionFee);
                    //调整费用
                    orderAdjustmentCost = orderAdjustmentCost.add(adjustmentCost);
                    //其他金额
                    orderOtherAmount = orderOtherAmount.add(otherAmount);
                    //已出单据金额
                    orderReceiptedAmount = orderReceiptedAmount.add(receiptedAmount);
                    //未收
                    orderRemainingReceivables = orderRemainingReceivables.add(remainingReceivables);
                }
            }
        }

        if (touristInfoSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristInfoService.saveBatch(touristInfoSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_408);
            }
        }
        /*if (otherFeeSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristOtherFeeService.saveBatch(otherFeeSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_408);
            }
        }*/
        if (adjustSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristFeeAdjustService.saveBatch(adjustSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_408);
            }
        }

        seriesOrder.setId(orderId);
        /*UserDTO saleMan = getSaleMan();
        if (saleMan != null) {
            seriesOrder.setSalesmanId(saleMan.getId());
            seriesOrder.setSalesmanName(saleMan.getFullName());
        }*/
        seriesOrder.setSalesmanId(req.getUserId());
        seriesOrder.setOrderNumber(getOrderNumber(req.getUserId()));
        seriesOrder.setPlusTouristType(PlusTouristTypeCode.DOWN.getCode());
        seriesOrder.setPlaceOrderStatus(PlaceOrderStatusCode.WAIT_CONFIRM.getCode());
        seriesOrder.setIsDeleted(IsDeletedCode.NO.getCode());
        seriesOrder.setGmtCreate(now);
        seriesOrder.setGmtModified(now);
        seriesOrder.setTotalPeople(totalPeople);
        seriesOrder.setTotalPrice(orderGroupFee);
        seriesOrder.setCreateId(req.getUserId());
        seriesOrder.setModifiedId(req.getUserId());
        if (Objects.equals(req.getOrderType(), OrderTypeCode.CLIENT.getCode())) {
            seriesOrder.setOrderSource(OrderSourceCode.CPM.getCode());
        } else if (Objects.equals(req.getOrderType(), OrderTypeCode.PROXY.getCode())) {
            seriesOrder.setOrderSource(OrderSourceCode.CPM_PROXY.getCode());
        }
        seriesOrder.setTripId(seriesTripScheduleDataDTO.getTripId());
        seriesOrder.setTripTitle(seriesTripScheduleDataDTO.getTitle());
        seriesOrder.setScheduleNumber(tripScheduleDTO.getTripNumber());
        seriesOrder.setDepartDate(tripScheduleDTO.getDepartureDate());
        seriesOrder.setScheduleStatus(tripScheduleDTO.getScheduleStatus());
        boolean save = save(seriesOrder);

        //统计
        SeriesOrderAmountStatistics statistics = new SeriesOrderAmountStatistics();
        statistics.setScheduleId(req.getScheduleId());
        statistics.setOrderId(orderId);
        statistics.setTotalTourFee(orderGroupFee);
        statistics.setTotalReceivables(orderTotalReceivables);
        statistics.setTotalPaidIn(orderTotalPaidIn);
        statistics.setRefundAmount(orderRefundAmount);
        statistics.setCollectionFee(orderCollectionFee);
        statistics.setAdjustmentCost(orderAdjustmentCost);
        statistics.setOtherAmount(orderOtherAmount);
        statistics.setReceiptedAmount(orderReceiptedAmount);
        statistics.setRemainingReceivables(orderRemainingReceivables);
        int insert = seriesOrderAmountStatisticsMapper.insert(statistics);

        if (!save || insert <= 0) {
            throw new BusinessException(SystemError.SYS_408);
        }

        /*JSONObject jsonObject = new JSONObject();
        jsonObject.put("orderId", seriesOrder.getId());
        OhMyClient taskClient = new OhMyClient(domain, appName, password);
        ResultDTO<Long> resultTask = taskClient.runJob(jobIdCloseOccupy, jsonObject.toJSONString(), Constants.DELAY_MS);
        if (!resultTask.isSuccess()) {
            throw new BusinessException(SystemError.SYS_500);
        }
        redisTemplate.opsForValue().set(RedisConstants.ORDER_TOUR_CLOSE_OCCUPY_ID_KEY + seriesOrder.getId(), resultTask.getData(), Constants.DELAY_MS, TimeUnit.MILLISECONDS);
        */
        SeriesOrderDTO seriesOrderDTO = EntityUtil.copy(seriesOrder, SeriesOrderDTO.class);
        return Result.success(seriesOrderDTO);
    }

    /**
     * 确认订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<SeriesOrderDTO> confirm(SeriesOrderConfirmReq seriesOrderConfirmReq) {
        SeriesOrder dbOrder = getById(seriesOrderConfirmReq.getId());
        if (!Objects.equals(PlusTouristTypeCode.DOWN.getCode(), dbOrder.getPlusTouristType())) {
            return Result.failed(SystemError.SYS_400);
        }
        if (!Objects.equals(PlaceOrderStatusCode.WAIT_CONFIRM.getCode(), dbOrder.getPlaceOrderStatus())) {
            return Result.failed(SeriesOrderErrorCode.STATUS_ERROR);
        }
        SeriesOrder seriesOrder = EntityUtil.copy(seriesOrderConfirmReq, SeriesOrder.class);
        seriesOrder.setPlaceOrderStatus(PlaceOrderStatusCode.CONFIRM.getCode());
        boolean update = updateById(seriesOrder);
        if (!update) {
            throw new BusinessException(SystemError.SYS_408);
        }
        SeriesOrderDTO seriesOrderDTO = EntityUtil.copy(seriesOrder, SeriesOrderDTO.class);

        /*Long instanceId = (Long) redisTemplate.opsForValue().get(RedisConstants.ORDER_TOUR_CLOSE_OCCUPY_ID_KEY + dbOrder.getId());
        if (instanceId != null) {
            OhMyClient taskClient = new OhMyClient(domain, appName, password);
            ResultDTO<Void> resultTask = taskClient.cancelInstance(instanceId);

            if (!resultTask.isSuccess()) {
                // 取消任务执行成功
                log.info("取消【关闭占位】任务,订单id[{}],任务实例id[{}]", dbOrder.getId(), instanceId);
            }
        }*/
        return Result.success(seriesOrderDTO);
    }

    /**
     * 追位
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<SeriesOrderDTO> additional(SeriesOrderAdditionalReq req) {
        //获取团期，判断是否能下单
        SeriesTripScheduleDTO tripScheduleDTO = iSeriesTripScheduleService.getTripScheduleId(req.getScheduleId());
        SeriesTripScheduleDataDTO seriesTripScheduleDataDTO = tripScheduleDTO.getSeriesTripScheduleDataDTO();
        SeriesTripScheduleTeamRuleDTO seriesTripScheduleTeamRuleDTO = tripScheduleDTO.getSeriesTripScheduleTeamRuleDTO();

        //++
        if (!EnableAdditional.YES.getCode().equals(seriesTripScheduleTeamRuleDTO.getEnableAdditionalPosition())) {
            return Result.failed(SeriesOrderErrorCode.ADD_ORDER_LIMIT);
        }
        //++

        //判断余位数是否充足
        if (req.getTouristList().size() > tripScheduleDTO.getReserveSeatNum().intValue()) {
            return Result.failed(SeriesOrderErrorCode.ADD_NUM_NOT_ENOUGH, tripScheduleDTO.getReserveSeatNum());
        }

        //检查游客类型
        BitSet bitSet = new BitSet();
        List<Passenger> passengerList = seriesTripScheduleTeamRuleDTO.getPassenger();
        int touristTypeSize = 0;
        for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
            for (Passenger passenger : passengerList) {
                if (Objects.equals(touristReq.getTouristTypeId(), passenger.getId())) {
                    bitSet.set(touristTypeSize);
                    break;
                }
            }
            touristTypeSize++;
        }
        if (touristTypeSize == bitSet.cardinality()) {
            return Result.failed(SeriesOrderErrorCode.DOWN_ORDER_TOURIST_LIMIT);
        }


        //占床数
        int occupyBedNum = 0;
        //不占床数
        int notOccupyBedNum = 0;
        for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
            //单房差
            for (Passenger passenger : seriesTripScheduleTeamRuleDTO.getPassenger()) {
                if (Objects.equals(passenger.getMainDataId(), touristReq.getTouristTypeId())) {
                    if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.YES.getCode())) {
                        occupyBedNum = occupyBedNum + touristReq.getPeople();
                    } else if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.NO.getCode())) {
                        notOccupyBedNum = notOccupyBedNum + touristReq.getPeople();
                    }
                }
            }
        }

        //计算最终所需房间数
        Map<String, Integer> roomsResult = SingleRoomUtil.computeRooms(occupyBedNum, notOccupyBedNum,
                req.getRoomNum(),
                (double) seriesTripScheduleTeamRuleDTO.getOccupyBedNum(),
                (double) seriesTripScheduleTeamRuleDTO.getNotOccupyBedNum());
        Integer rooms = roomsResult.get("rooms");
        Integer singleRoomNum = roomsResult.get("singleRoomNum");


        long orderId = SnowflakeIdWorker.nextId();
        LocalDateTime now = LocalDateTime.now();
        SeriesOrder seriesOrder = EntityUtil.copy(req, SeriesOrder.class);

        List<SeriesOrderTouristInfoSaveBatchReq> touristInfoSaveBatchReqList = new ArrayList<>();
        List<SeriesOrderTouristOtherFeeSaveBatchReq> otherFeeSaveBatchReqList = new ArrayList<>();
        List<SeriesOrderTouristFeeAdjustSaveBatchReq> adjustSaveBatchReqList = new ArrayList<>();

        //团费
        BigDecimal orderGroupFee = new BigDecimal(0);
        //应收
        BigDecimal orderTotalReceivables = new BigDecimal(0);
        //实收
        BigDecimal orderTotalPaidIn = new BigDecimal(0);
        //已退款
        BigDecimal orderRefundAmount = new BigDecimal(0);
        //代收费用
        BigDecimal orderCollectionFee = new BigDecimal(0);
        //调整费用
        BigDecimal orderAdjustmentCost = new BigDecimal(0);
        //其他金额
        BigDecimal orderOtherAmount = new BigDecimal(0);
        //已出单据金额
        BigDecimal orderReceiptedAmount = new BigDecimal(0);
        //未收
        BigDecimal orderRemainingReceivables = new BigDecimal(0);
        //人数
        Integer totalPeople = 0;
        if (Objects.equals(tripScheduleDTO.getCostSharingType(), CostSharingType.DEFAULT.getCode())) {
            //默认模板
            TripScheduleDefaultCostDTO tripScheduleDefaultCostDTO = tripScheduleDTO.getTripScheduleDefaultCost();
            SeriesTripScheduleSellingPriceDTO seriesTripScheduleSellingPriceDTO = tripScheduleDefaultCostDTO.getSeriesTripScheduleSellingPriceDTO();
            List<SeriesTripScheduleDefaultCostCollectionDTO> costCollectionList = tripScheduleDefaultCostDTO.getCostCollectionList();
            List<SeriesTripScheduleDefaultFeeAdjustDTO> feeAdjustList = tripScheduleDefaultCostDTO.getFeeAdjustList();

            //单房差
            SeriesTripScheduleDefaultFeeAdjustDTO singleRoomAdjustDTO = null;
            if (CollectionUtils.isNotEmpty(feeAdjustList)) {
                for (SeriesTripScheduleDefaultFeeAdjustDTO seriesTripScheduleDefaultFeeAdjustDTO : feeAdjustList) {
                    if (Objects.equals(seriesTripScheduleDefaultFeeAdjustDTO.getMainDataId(), Constants.SINGLE_ROOM_ID)) {
                        singleRoomAdjustDTO = seriesTripScheduleDefaultFeeAdjustDTO;
                        break;
                    }
                }
            }


            for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
                for (int i = 0; i < touristReq.getPeople(); i++) {
                    long touristId = IdWorker.getId();
                    List<TouristCollectionFeeJson> collectionFeeJsonList = new ArrayList<>();
                    SeriesOrderTouristInfoSaveBatchReq touristInfoSaveBatchReq = new SeriesOrderTouristInfoSaveBatchReq();

                    //团费
                    BigDecimal groupFee = seriesTripScheduleSellingPriceDTO.getGroupCustomerPrice();
                    //获取加幅后的团费
                    //下单类型（0 直客下单，1 代理商下单）
                    if (Objects.equals(req.getOrderType(), 0)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getUserId());
                    } else if (Objects.equals(req.getOrderType(), 1)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getAgentId());
                    }
                    //应收
                    BigDecimal totalReceivables = new BigDecimal(0);
                    //实收
                    BigDecimal totalPaidIn = new BigDecimal(0);
                    //已退款
                    BigDecimal refundAmount = new BigDecimal(0);
                    //代收费用
                    BigDecimal collectionFee = new BigDecimal(0);
                    //调整费用
                    BigDecimal adjustmentCost = new BigDecimal(0);
                    //其他金额
                    BigDecimal otherAmount = new BigDecimal(0);
                    //已出单据金额
                    BigDecimal receiptedAmount = new BigDecimal(0);
                    //未收
                    BigDecimal remainingReceivables = new BigDecimal(0);

                    if (CollectionUtils.isNotEmpty(costCollectionList)) {
                        for (SeriesTripScheduleDefaultCostCollectionDTO seriesTripScheduleDefaultCostCollectionDTO : costCollectionList) {
                            SeriesTripScheduleDefaultCostTouristTypeDTO selectTypeDTO = null;

                            //判断代收费用中是否有相同游客类型的代收费用
                            for (SeriesTripScheduleDefaultCostTouristTypeDTO typeDTO : seriesTripScheduleDefaultCostCollectionDTO.getCostCollectionTypeList()) {
                                if (Objects.equals(typeDTO.getTouristTypeId(), touristReq.getTouristTypeId())) {
                                    selectTypeDTO = typeDTO;
                                    break;
                                }
                            }

                            if (selectTypeDTO == null) {
                                continue;
                            }

                            TouristCollectionFeeJson collectionFeeJson = new TouristCollectionFeeJson();
                            collectionFeeJson.setProjectName(seriesTripScheduleDefaultCostCollectionDTO.getProjectName());
                            collectionFeeJson.setMainDataId(seriesTripScheduleDefaultCostCollectionDTO.getMainDataId());
                            collectionFeeJson.setAdjustType(1);
                            collectionFeeJson.setTotalAmount(selectTypeDTO.getTotalAmount().multiply(new BigDecimal(seriesTripScheduleDefaultCostCollectionDTO.getExchangeRate())).setScale(2, BigDecimal.ROUND_HALF_UP));
                            collectionFeeJsonList.add(collectionFeeJson);

                            //如有,将行程代收费保存用到(订单)代收费用
                            /*SeriesOrderTouristOtherFeeSaveBatchReq otherFeeSaveBatchReq = new SeriesOrderTouristOtherFeeSaveBatchReq();
                            otherFeeSaveBatchReq.setFeeType(SeriesOrderTouristOtherFeeFeeTypeCode.COLLECTION.getCode());
                            otherFeeSaveBatchReq.setOrderId(orderId);
                            otherFeeSaveBatchReq.setTouristId(touristId);
                            otherFeeSaveBatchReq.setFeeName(seriesTripScheduleDefaultCostCollectionDTO.getProjectName());
                            otherFeeSaveBatchReq.setRelationId(seriesTripScheduleDefaultCostCollectionDTO.getId());
                            otherFeeSaveBatchReq.setAmount(selectTypeDTO.getTotalAmount());
                            otherFeeSaveBatchReq.setGmtCreate(now);
                            otherFeeSaveBatchReq.setGmtModified(now);
                            otherFeeSaveBatchReq.setCreateId(req.getUserId());
                            otherFeeSaveBatchReq.setModifiedId(req.getUserId());
                            otherFeeSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                            otherFeeSaveBatchReqList.add(otherFeeSaveBatchReq);*/

                            //累计代收费用
                            collectionFee = collectionFee.add(selectTypeDTO.getTotalAmount());
                        }
                    }

                    if (collectionFeeJsonList.size() > 0) {
                        touristInfoSaveBatchReq.setCollectionFeeJson(JSON.toJSONString(collectionFeeJsonList));
                    }

                    //其他费用


                    //调整费用
                    if (singleRoomAdjustDTO != null && singleRoomNum > 0) {
                        SeriesOrderTouristFeeAdjustSaveBatchReq seriesOrderTouristFeeAdjust = new SeriesOrderTouristFeeAdjustSaveBatchReq();
                        seriesOrderTouristFeeAdjust.setRelationId(singleRoomAdjustDTO.getId());
                        seriesOrderTouristFeeAdjust.setAmount(singleRoomAdjustDTO.getCostAmount());
                        seriesOrderTouristFeeAdjust.setPlusType(singleRoomAdjustDTO.getAdjustType());
                        seriesOrderTouristFeeAdjust.setName(singleRoomAdjustDTO.getProjectName());
                        seriesOrderTouristFeeAdjust.setTouristId(touristId);
                        seriesOrderTouristFeeAdjust.setAdjustType(AdjustTypeCode.ADJUST.getCode());
                        seriesOrderTouristFeeAdjust.setOrderId(orderId);
                        seriesOrderTouristFeeAdjust.setUserId(req.getUserId());
                        adjustSaveBatchReqList.add(seriesOrderTouristFeeAdjust);

                        singleRoomNum--;

                        //累计调整费用
                        if (Objects.equals(singleRoomAdjustDTO.getAdjustType(), PlusTypeCode.PLUS.getCode())) {
                            adjustmentCost = adjustmentCost.add(singleRoomAdjustDTO.getCostAmount());
                        } else if (Objects.equals(singleRoomAdjustDTO.getAdjustType(), PlusTypeCode.SUBTRACT.getCode())) {
                            adjustmentCost = adjustmentCost.subtract(singleRoomAdjustDTO.getCostAmount());
                        }
                    }

                    //应收=团费+代收+调整+其他
                    totalReceivables = ((groupFee.add(collectionFee)).add(adjustmentCost)).add(otherAmount);
                    //未收=应收-实收
                    remainingReceivables = totalReceivables.subtract(totalPaidIn);

                    touristInfoSaveBatchReq.setId(touristId);
                    touristInfoSaveBatchReq.setOrderId(orderId);
                    touristInfoSaveBatchReq.setScheduleId(seriesOrder.getScheduleId());
                    touristInfoSaveBatchReq.setMainDataId(touristReq.getTouristTypeId());
                    touristInfoSaveBatchReq.setTouristTypeName(touristReq.getTouristTypeName());
                    touristInfoSaveBatchReq.setPayStatus(PayStatusCode.WAIT.getCode());
                    touristInfoSaveBatchReq.setNoshow(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setLockStatus(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                    touristInfoSaveBatchReq.setGmtCreate(now);
                    touristInfoSaveBatchReq.setGmtModified(now);
                    touristInfoSaveBatchReq.setCreateId(req.getUserId());
                    touristInfoSaveBatchReq.setModifiedId(req.getUserId());
                    touristInfoSaveBatchReq.setIsFullInfo(ISCode.NO.getCode());
                    //订单统计
                    touristInfoSaveBatchReq.setGroupFee(groupFee);
                    touristInfoSaveBatchReq.setTotalReceivables(totalReceivables);
                    touristInfoSaveBatchReq.setTotalPaidIn(totalPaidIn);
                    touristInfoSaveBatchReq.setRefundAmount(refundAmount);
                    touristInfoSaveBatchReq.setCollectionFee(collectionFee);
                    touristInfoSaveBatchReq.setAdjustmentCost(adjustmentCost);
                    touristInfoSaveBatchReq.setOtherAmount(otherAmount);
                    touristInfoSaveBatchReq.setReceiptedAmount(receiptedAmount);
                    touristInfoSaveBatchReq.setRemainingReceivables(remainingReceivables);
                    touristInfoSaveBatchReq.setIsReceiptCalculated(ISCode.NO.getCode());
                    touristInfoSaveBatchReq.setBuyInsurance(ISCode.NO.getCode());
                    touristInfoSaveBatchReqList.add(touristInfoSaveBatchReq);

                    //人数
                    totalPeople++;
                    //团费
                    orderGroupFee = orderGroupFee.add(groupFee);
                    //应收
                    orderTotalReceivables = orderTotalReceivables.add(totalReceivables);
                    //实收
                    orderTotalPaidIn = orderTotalPaidIn.add(totalPaidIn);
                    //已退款
                    orderRefundAmount = orderRefundAmount.add(refundAmount);
                    //代收费用
                    orderCollectionFee = orderCollectionFee.add(collectionFee);
                    //调整费用
                    orderAdjustmentCost = orderAdjustmentCost.add(adjustmentCost);
                    //其他金额
                    orderOtherAmount = orderOtherAmount.add(otherAmount);
                    //已出单据金额
                    orderReceiptedAmount = orderReceiptedAmount.add(receiptedAmount);
                    //未收
                    orderRemainingReceivables = orderRemainingReceivables.add(remainingReceivables);

                }
            }
        } else if (Objects.equals(tripScheduleDTO.getCostSharingType(), CostSharingType.CUSTOM.getCode())) {
            //自定义
            TripCustomCostReq tripCustomCostReq = tripScheduleDTO.getTripCustomCostReq();
            List<TripCustomSalePriceReq> customSalePriceList = tripCustomCostReq.getCustomSalePriceList();
            ;
            List<SeriesTripDefaultCostCollectionReq> customCostCollectionList = tripCustomCostReq.getCostCollectionList();
            List<SeriesTripCustomFeeAdjustReq> customFeeAdjustList = tripCustomCostReq.getFeeAdjustList();

            for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
                //团费
                TripCustomSalePriceReq selectTripCustomSalePriceReq = null;
                A:
                for (TripCustomSalePriceReq tripCustomSalePriceReq : customSalePriceList) {
                    if (Objects.equals(tripCustomSalePriceReq.getMainDataId(), touristReq.getTouristTypeId())) {
                        if (Objects.equals(tripCustomSalePriceReq.getDateType(), DataType.WEEK.getCode())) {
                            for (Integer checkWeekDay : tripCustomSalePriceReq.getCheckWeekDays()) {
                                if (Objects.equals(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue(), checkWeekDay)) {
                                    selectTripCustomSalePriceReq = tripCustomSalePriceReq;
                                    break A;
                                }
                            }
                        } else if (Objects.equals(tripCustomSalePriceReq.getDateType(), DataType.DATE.getCode())) {
                            if (tripScheduleDTO.getDepartureDate().compareTo(tripCustomSalePriceReq.getDateBegin()) >= 0
                                    && tripScheduleDTO.getDepartureDate().compareTo(tripCustomSalePriceReq.getDateEnd()) <= 0) {
                                selectTripCustomSalePriceReq = tripCustomSalePriceReq;
                                break A;
                            }
                        }
                    }
                }
                if (selectTripCustomSalePriceReq == null) {
                    throw new BusinessException(SystemError.SYS_411);
                }

                //单房差
                SeriesTripCustomFeeAdjustReq singleRoomCustomFeeAdjustReq = null;
                CustomCostReq singleRoomCustomCostReq = null;
                B:
                if (CollectionUtils.isNotEmpty(customFeeAdjustList)) {
                    for (SeriesTripCustomFeeAdjustReq seriesTripCustomFeeAdjustReq : customFeeAdjustList) {
                        if (Objects.equals(seriesTripCustomFeeAdjustReq.getMainDataId(), Constants.SINGLE_ROOM_ID)) {
                            for (CustomCostReq customCostReq : seriesTripCustomFeeAdjustReq.getCustomCostList()) {
                                if (Objects.equals(customCostReq.getMainDataId(), touristReq.getTouristTypeId())) {
                                    if (Objects.equals(customCostReq.getDateType(), DataType.WEEK.getCode())) {
                                        for (Integer checkWeekDay : customCostReq.getCheckWeekDays()) {
                                            if (Objects.equals(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue(), checkWeekDay)) {
                                                singleRoomCustomFeeAdjustReq = seriesTripCustomFeeAdjustReq;
                                                singleRoomCustomCostReq = customCostReq;
                                                break B;
                                            }
                                        }
                                    } else if (Objects.equals(customCostReq.getDateType(), DataType.DATE.getCode())) {
                                        if (tripScheduleDTO.getDepartureDate().compareTo(customCostReq.getDateBegin()) >= 0
                                                && tripScheduleDTO.getDepartureDate().compareTo(customCostReq.getDateEnd()) <= 0) {
                                            singleRoomCustomFeeAdjustReq = seriesTripCustomFeeAdjustReq;
                                            singleRoomCustomCostReq = customCostReq;
                                            break B;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }


                for (int i = 0; i < touristReq.getPeople(); i++) {
                    long touristId = IdWorker.getId();
                    SeriesOrderTouristInfoSaveBatchReq touristInfoSaveBatchReq = new SeriesOrderTouristInfoSaveBatchReq();
                    List<TouristCollectionFeeJson> collectionFeeJsonList = new ArrayList<>();

                    //团费
                    BigDecimal groupFee = selectTripCustomSalePriceReq.getGroupCustomerPrice();
                    //获取加幅后的团费
                    //下单类型（0 直客下单，1 代理商下单）
                    if (Objects.equals(req.getOrderType(), 0)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getUserId());
                    } else if (Objects.equals(req.getOrderType(), 1)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getAgentId());
                    }
                    //应收
                    BigDecimal totalReceivables = new BigDecimal(0);
                    //实收
                    BigDecimal totalPaidIn = new BigDecimal(0);
                    //已退款
                    BigDecimal refundAmount = new BigDecimal(0);
                    //代收费用
                    BigDecimal collectionFee = new BigDecimal(0);
                    //调整费用
                    BigDecimal adjustmentCost = new BigDecimal(0);
                    //其他金额
                    BigDecimal otherAmount = new BigDecimal(0);
                    //已出单据金额
                    BigDecimal receiptedAmount = new BigDecimal(0);
                    //未收
                    BigDecimal remainingReceivables = new BigDecimal(0);

                    if (CollectionUtils.isNotEmpty(customCostCollectionList)) {
                        for (SeriesTripDefaultCostCollectionReq seriesTripDefaultCostCollectionReq : customCostCollectionList) {
                            SeriesTripDefaultCostCollectionTypeReq selectTypeDTO = null;

                            //判断代收费用中是否有相同游客类型的代收费用
                            for (SeriesTripDefaultCostCollectionTypeReq typeDTO : seriesTripDefaultCostCollectionReq.getCostCollectionTypeList()) {
                                if (Objects.equals(typeDTO.getTouristTypeId(), touristReq.getTouristTypeId())) {
                                    selectTypeDTO = typeDTO;
                                    break;
                                }
                            }

                            if (selectTypeDTO == null) {
                                continue;
                            }

                            TouristCollectionFeeJson collectionFeeJson = new TouristCollectionFeeJson();
                            collectionFeeJson.setProjectName(seriesTripDefaultCostCollectionReq.getProjectName());
                            collectionFeeJson.setMainDataId(seriesTripDefaultCostCollectionReq.getMainDataId());
                            collectionFeeJson.setAdjustType(1);
                            collectionFeeJson.setTotalAmount(selectTypeDTO.getTotalAmount().multiply(new BigDecimal(seriesTripDefaultCostCollectionReq.getExchangeRate())).setScale(2, BigDecimal.ROUND_HALF_UP));
                            collectionFeeJsonList.add(collectionFeeJson);

                            //如有,将行程代收费保存用到(订单)代收费用
                            /*SeriesOrderTouristOtherFeeSaveBatchReq otherFeeSaveBatchReq = new SeriesOrderTouristOtherFeeSaveBatchReq();
                            otherFeeSaveBatchReq.setFeeType(SeriesOrderTouristOtherFeeFeeTypeCode.COLLECTION.getCode());
                            otherFeeSaveBatchReq.setOrderId(orderId);
                            otherFeeSaveBatchReq.setTouristId(touristId);
                            otherFeeSaveBatchReq.setFeeName(seriesTripDefaultCostCollectionReq.getProjectName());
                            otherFeeSaveBatchReq.setRelationId(seriesTripDefaultCostCollectionReq.getId());
                            otherFeeSaveBatchReq.setAmount(selectTypeDTO.getTotalAmount());
                            otherFeeSaveBatchReq.setGmtCreate(now);
                            otherFeeSaveBatchReq.setGmtModified(now);
                            otherFeeSaveBatchReq.setCreateId(req.getUserId());
                            otherFeeSaveBatchReq.setModifiedId(req.getUserId());
                            otherFeeSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                            otherFeeSaveBatchReqList.add(otherFeeSaveBatchReq);*/

                            //累计代收费用
                            collectionFee = collectionFee.add(selectTypeDTO.getTotalAmount());
                        }
                    }

                    if (collectionFeeJsonList.size() > 0) {
                        touristInfoSaveBatchReq.setCollectionFeeJson(JSON.toJSONString(collectionFeeJsonList));
                    }
                    //其他费用


                    //调整费用
                    if (singleRoomCustomFeeAdjustReq != null && singleRoomCustomCostReq != null &&
                            singleRoomNum > 0) {
                        SeriesOrderTouristFeeAdjustSaveBatchReq seriesOrderTouristFeeAdjust = new SeriesOrderTouristFeeAdjustSaveBatchReq();
                        seriesOrderTouristFeeAdjust.setRelationId(singleRoomCustomFeeAdjustReq.getId());
                        seriesOrderTouristFeeAdjust.setAmount(singleRoomCustomCostReq.getPrice());
                        seriesOrderTouristFeeAdjust.setPlusType(singleRoomCustomFeeAdjustReq.getAdjustType());
                        seriesOrderTouristFeeAdjust.setName(singleRoomCustomFeeAdjustReq.getProjectName());
                        seriesOrderTouristFeeAdjust.setTouristId(touristId);
                        seriesOrderTouristFeeAdjust.setAdjustType(AdjustTypeCode.ADJUST.getCode());
                        seriesOrderTouristFeeAdjust.setOrderId(orderId);
                        seriesOrderTouristFeeAdjust.setUserId(req.getUserId());
                        adjustSaveBatchReqList.add(seriesOrderTouristFeeAdjust);

                        singleRoomNum--;

                        //累计调整费用
                        if (Objects.equals(singleRoomCustomFeeAdjustReq.getAdjustType(), PlusTypeCode.PLUS.getCode())) {
                            adjustmentCost = adjustmentCost.add(singleRoomCustomCostReq.getPrice());
                        } else if (Objects.equals(singleRoomCustomFeeAdjustReq.getAdjustType(), PlusTypeCode.SUBTRACT.getCode())) {
                            adjustmentCost = adjustmentCost.subtract(singleRoomCustomCostReq.getPrice());
                        }
                    }

                    //应收=团费+代收+调整+其他
                    totalReceivables = ((groupFee.add(collectionFee)).add(adjustmentCost)).add(otherAmount);
                    //未收=应收-实收
                    remainingReceivables = totalReceivables.subtract(totalPaidIn);

                    touristInfoSaveBatchReq.setId(touristId);
                    touristInfoSaveBatchReq.setOrderId(orderId);
                    touristInfoSaveBatchReq.setScheduleId(seriesOrder.getScheduleId());
                    touristInfoSaveBatchReq.setMainDataId(touristReq.getTouristTypeId());
                    touristInfoSaveBatchReq.setPayStatus(PayStatusCode.WAIT.getCode());
                    touristInfoSaveBatchReq.setNoshow(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setLockStatus(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                    touristInfoSaveBatchReq.setGmtCreate(now);
                    touristInfoSaveBatchReq.setGmtModified(now);
                    touristInfoSaveBatchReq.setCreateId(req.getUserId());
                    touristInfoSaveBatchReq.setModifiedId(req.getUserId());
                    touristInfoSaveBatchReq.setIsFullInfo(ISCode.NO.getCode());
                    //订单统计
                    touristInfoSaveBatchReq.setGroupFee(groupFee);
                    touristInfoSaveBatchReq.setTotalReceivables(totalReceivables);
                    touristInfoSaveBatchReq.setTotalPaidIn(totalPaidIn);
                    touristInfoSaveBatchReq.setRefundAmount(refundAmount);
                    touristInfoSaveBatchReq.setCollectionFee(collectionFee);
                    touristInfoSaveBatchReq.setAdjustmentCost(adjustmentCost);
                    touristInfoSaveBatchReq.setOtherAmount(otherAmount);
                    touristInfoSaveBatchReq.setReceiptedAmount(receiptedAmount);
                    touristInfoSaveBatchReq.setRemainingReceivables(remainingReceivables);
                    touristInfoSaveBatchReq.setIsReceiptCalculated(ISCode.NO.getCode());
                    touristInfoSaveBatchReq.setBuyInsurance(ISCode.NO.getCode());
                    touristInfoSaveBatchReqList.add(touristInfoSaveBatchReq);

                    //人数
                    totalPeople++;
                    //团费
                    orderGroupFee = orderGroupFee.add(groupFee);
                    //应收
                    orderTotalReceivables = orderTotalReceivables.add(totalReceivables);
                    //实收
                    orderTotalPaidIn = orderTotalPaidIn.add(totalPaidIn);
                    //已退款
                    orderRefundAmount = orderRefundAmount.add(refundAmount);
                    //代收费用
                    orderCollectionFee = orderCollectionFee.add(collectionFee);
                    //调整费用
                    orderAdjustmentCost = orderAdjustmentCost.add(adjustmentCost);
                    //其他金额
                    orderOtherAmount = orderOtherAmount.add(otherAmount);
                    //已出单据金额
                    orderReceiptedAmount = orderReceiptedAmount.add(receiptedAmount);
                    //未收
                    orderRemainingReceivables = orderRemainingReceivables.add(remainingReceivables);

                }
            }
        }
        if (touristInfoSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristInfoService.saveBatch(touristInfoSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_408);
            }
        }
        if (otherFeeSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristOtherFeeService.saveBatch(otherFeeSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_408);
            }
        }
        if (adjustSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristFeeAdjustService.saveBatch(adjustSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_408);
            }
        }

        seriesOrder.setId(orderId);
        seriesOrder.setSalesmanId(req.getUserId());
        seriesOrder.setOrderNumber(getOrderNumber(req.getUserId()));
        seriesOrder.setPlusTouristType(PlusTouristTypeCode.ADD.getCode());//++
        seriesOrder.setPlaceOrderStatus(PlaceOrderStatusCode.WAIT_CONFIRM.getCode());
        seriesOrder.setIsDeleted(IsDeletedCode.NO.getCode());
        seriesOrder.setGmtCreate(now);
        seriesOrder.setGmtModified(now);
        seriesOrder.setTotalPeople(totalPeople);
        seriesOrder.setTotalPrice(orderGroupFee);
        seriesOrder.setCreateId(req.getUserId());
        seriesOrder.setModifiedId(req.getUserId());
        if (Objects.equals(req.getOrderType(), OrderTypeCode.CLIENT.getCode())) {
            seriesOrder.setOrderSource(OrderSourceCode.CPM.getCode());
        } else if (Objects.equals(req.getOrderType(), OrderTypeCode.PROXY.getCode())) {
            seriesOrder.setOrderSource(OrderSourceCode.CPM_PROXY.getCode());
        }
        seriesOrder.setTripId(seriesTripScheduleDataDTO.getTripId());
        seriesOrder.setTripTitle(seriesTripScheduleDataDTO.getTitle());
        seriesOrder.setScheduleNumber(tripScheduleDTO.getTripNumber());
        seriesOrder.setDepartDate(tripScheduleDTO.getDepartureDate());
        seriesOrder.setScheduleStatus(tripScheduleDTO.getScheduleStatus());
        boolean save = save(seriesOrder);
        if (!save) {
            throw new BusinessException(SystemError.SYS_437);
        }

        //统计
        SeriesOrderAmountStatistics statistics = new SeriesOrderAmountStatistics();
        statistics.setScheduleId(req.getScheduleId());
        statistics.setOrderId(orderId);
        statistics.setTotalTourFee(orderGroupFee);
        statistics.setTotalReceivables(orderTotalReceivables);
        statistics.setTotalPaidIn(orderTotalPaidIn);
        statistics.setRefundAmount(orderRefundAmount);
        statistics.setCollectionFee(orderCollectionFee);
        statistics.setAdjustmentCost(orderAdjustmentCost);
        statistics.setOtherAmount(orderOtherAmount);
        statistics.setReceiptedAmount(orderReceiptedAmount);
        statistics.setRemainingReceivables(orderRemainingReceivables);
        int insert = seriesOrderAmountStatisticsMapper.insert(statistics);
        if (insert <= 0) {
            throw new BusinessException(SystemError.SYS_437);
        }

        SeriesOrderDTO seriesOrderDTO = EntityUtil.copy(seriesOrder, SeriesOrderDTO.class);
        return Result.success(seriesOrderDTO);
    }

    /**
     * 追位审核
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result additionalApproval(SeriesOrderAdditionalApprovalReq req, TokenUser tokenUser) {
        if (!ApprovalStatus.isCheckStatus(req.getApprovalStatus())) {
            return Result.failed(SeriesOrderErrorCode.STATUS_ERROR);
        }
        QueryWrapper<SeriesOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("approval_id", req.getApprovalId());
        queryWrapper.eq("is_deleted", 0);
        SeriesOrder dbOrder = seriesOrderMapper.selectOne(queryWrapper);
        if (dbOrder == null) {
            return Result.failed(SystemError.SYS_411);
        }
        if (!Objects.equals(dbOrder.getPlaceOrderStatus(), 2)) {
            throw new BusinessException(SystemError.FINANCE_BILL_17012);
        }
        Result<ApprovalCheckDTO> result = iSysApprovalService.check(req.getApprovalId(), req.getUserId(),
                req.getApprovalStatus(), req.getComments());
        if (!result.isSuccess()) {
            return Result.failed(SystemError.SYS_500);
        }
        if (result.getData() != null) {
            if (result.getData().getIsFinish() && Objects.equals(req.getApprovalStatus(), ApprovalStatus.REVIEW_YES.getCode())) {
                //最大成圖人數變為（最大成團人數+追位人數）
                UpdateSchedulePassengerReq updateSchedulePassengerReq = new UpdateSchedulePassengerReq();
                updateSchedulePassengerReq.setId(dbOrder.getScheduleId());
                updateSchedulePassengerReq.setType(UpdateSchedulePassengerTypeCode.ADD.getCode());
                updateSchedulePassengerReq.setLockedTouristNum(dbOrder.getTotalPeople());
                Result updateResult = iSeriesTripScheduleService.updateSchedulePassengerReq(updateSchedulePassengerReq, tokenUser);
                if (!updateResult.isSuccess()) {
                    return updateResult;
                }

                dbOrder.setPlaceOrderStatus(PlaceOrderStatusCode.CONFIRM.getCode());
            } else if (Objects.equals(req.getApprovalStatus(), ApprovalStatus.REVIEW_NO.getCode())) {
                dbOrder.setPlaceOrderStatus(PlaceOrderStatusCode.APPROVAL_NOT_PASS.getCode());
            } else if (Objects.equals(req.getApprovalStatus(), ApprovalStatus.RECALL.getCode())) {
                dbOrder.setPlaceOrderStatus(PlaceOrderStatusCode.APPROVAL_NOT_PASS.getCode());
            }
            boolean update = updateById(dbOrder);
            if (!update) {
                throw new BusinessException(SystemError.SYS_437);
            }
        }
        return Result.success(dbOrder.getId());
    }

    /**
     * 列表
     */
    @Override
    public Result<SeriesOrderListDTO> list(SeriesOrderListReq req, TokenUser currentUser) {
        if (Objects.equals(req.getIsMy(), ISCode.YES.getCode())) {
            req.setMyId(currentUser.getId());
        }
        if (req.getStartTime() == null && req.getEndTime() == null) {
            req.setEndTime(LocalDate.now().plusDays(1L));
            req.setStartTime(LocalDate.now().minusDays(30L));
        }
        Result<List<Long>> permission = iSysPermissionService.queryPermission(req.getMenuId(), currentUser.getId());
        if (!permission.isSuccess() || CollectionUtils.isEmpty(permission.getData())) {
            throw new BusinessException(SystemError.USER_1001);
        }
        List<Long> authUserIdList = permission.getData();
//        authUserIdList.add(1L);
        req.setAuthUserIdList(authUserIdList);

        SeriesOrderListDTO seriesOrderListDTO = seriesOrderMapper.selectCountBySelective(req);
        if (seriesOrderListDTO == null) {
            seriesOrderListDTO = new SeriesOrderListDTO();
            seriesOrderListDTO.setRemainingReceivables(BigDecimal.ZERO);
            seriesOrderListDTO.setTotalPaidIn(BigDecimal.ZERO);
            seriesOrderListDTO.setRemainingReceivables(BigDecimal.ZERO);
            seriesOrderListDTO.setTotalPeople(0);
        }
        IPage<SeriesOrderListReq> page = new Page<>(req.getPageNo(), req.getPageSize());
        IPage<SeriesOrderPageDTO> seriesOrderDTOIPage = seriesOrderMapper.selectListBySelective(page, req);

        List<SeriesOrderPageDTO> records = seriesOrderDTOIPage.getRecords();
        List<Long> listId = new ArrayList<>();
        for (SeriesOrderPageDTO record : records) {
            if (record.getScheduleId() != null) {
                listId.add(record.getScheduleId());
            }
        }
        if (records.size() > 0) {
            TripScheduleListIdReq tripScheduleListIdReq = new TripScheduleListIdReq();
            tripScheduleListIdReq.setListId(listId);
            List<TripScheduleListDTO> tripScheduleList = iSeriesTripScheduleService.getTripScheduleList(tripScheduleListIdReq);
            for (SeriesOrderPageDTO record : records) {
                //收客情况
                List<SeriesOrderPageTouristPeopleDTO> touristPeopleList = seriesOrderTouristInfoMapper.queryCount(record.getId());
                record.setTouristPeopleList2(touristPeopleList);
                //销售人员
                if (record.getCreateId() != null) {
                    UserDTO createUser = iSysUserService.queryCacheUser(record.getCreateId());
                    if (createUser != null) {
                        record.setCreateName(createUser.getFullName());
                        record.setCreateDept(createUser.getDept());
                    }
                } else if (record.getSalesmanId() != null) {
                    UserDTO createUser = iSysUserService.queryCacheUser(record.getSalesmanId());
                    if (createUser != null) {
                        record.setCreateName(createUser.getFullName());
                        record.setCreateDept(createUser.getDept());
                    }
                }

                if (Objects.equals(record.getPlusTouristType(), PlusTouristTypeCode.DOWN.getCode())) {
                    record.setIsKeep(ISCode.NO.getCode());
                    record.setIsAdd(ISCode.NO.getCode());
                } else if (Objects.equals(record.getPlusTouristType(), PlusTouristTypeCode.KEEP.getCode())) {
                    if (record.getTotalPaidIn().compareTo(new BigDecimal(0)) > 0) {
                        record.setIsKeep(ISCode.NO.getCode());
                    } else {
                        record.setIsKeep(ISCode.YES.getCode());
                    }
                    record.setIsAdd(ISCode.NO.getCode());
                } else if (Objects.equals(record.getPlusTouristType(), PlusTouristTypeCode.ADD.getCode())) {
                    record.setIsKeep(ISCode.NO.getCode());
                    record.setIsAdd(ISCode.YES.getCode());
                    /*if (Objects.equals(record.getPlaceOrderStatus(), PlaceOrderStatusCode.APPROVAL.getCode())) {
                        record.setIsAdd(PlaceOrderStatusCode.APPROVAL.getCode());
                    } else if (Objects.equals(record.getPlaceOrderStatus(), PlaceOrderStatusCode.APPROVAL_PASS.getCode())) {
                        record.setIsAdd(PlaceOrderStatusCode.APPROVAL_PASS.getCode());
                    } else if (Objects.equals(record.getPlaceOrderStatus(), PlaceOrderStatusCode.APPROVAL_NOT_PASS.getCode())) {
                        record.setIsAdd(PlaceOrderStatusCode.APPROVAL_NOT_PASS.getCode());
                    }*/
                }
                for (TripScheduleListDTO tripScheduleListDTO : tripScheduleList) {
                    record.setScheduleStatus(tripScheduleListDTO.getScheduleStatus());
                    if (Objects.equals(record.getScheduleId(), tripScheduleListDTO.getId())) {
                        if (record.getRemainingReceivables().compareTo(BigDecimal.ZERO) > 0) {
                            //还有未收款
                            if (record.getTotalPaidIn().compareTo(new BigDecimal(0)) == 0) {
                                //待付款
                                LocalDateTime orderDateTime = record.getGmtCreate();
                                if (Objects.equals(record.getIsKeep(), ISCode.YES.getCode())) {
                                    //留位订单
                                    if (tripScheduleListDTO.getClearSeatsTime() != null && tripScheduleListDTO.getClearSeatsUnit() != null) {
                                        long clearSeatsTime = Long.parseLong(tripScheduleListDTO.getClearSeatsTime());
                                        if (Objects.equals(tripScheduleListDTO.getClearSeatsUnit(), ClearSeatsUnitCode.MINUTES.getCode())) {
                                            orderDateTime = orderDateTime.plusMinutes(clearSeatsTime);
                                        } else if (Objects.equals(tripScheduleListDTO.getClearSeatsUnit(), ClearSeatsUnitCode.HOUR.getCode())) {
                                            orderDateTime = orderDateTime.plusHours(clearSeatsTime);
                                        }
                                        if (LocalDateTime.now().compareTo(orderDateTime) <= 0) {
                                            record.setRemainingReceivablesRemark(orderDateTime.format(DateTimeFormatter.ofPattern(Utils.HH_mm_ss)) + " 前付款");
                                        }
                                    }
                                }
                            } else if (record.getTotalPaidIn().compareTo(new BigDecimal(0)) > 0) {
                                //待付余款
                                LocalDateTime orderDateTime = record.getGmtCreate();
                                if (tripScheduleListDTO.getDeliveryDays() != null) {
                                    orderDateTime = orderDateTime.plusDays(tripScheduleListDTO.getDeliveryDays());
                                    if (LocalDateTime.now().compareTo(orderDateTime) > 0) {
                                        record.setRemainingReceivablesRemark("已超时");
                                    } else {
                                        record.setRemainingReceivablesRemark(orderDateTime.format(DateTimeFormatter.ofPattern(Utils.yyyy_MM_dd)) + " 前付款");
                                    }
                                }
                            }
                        }
                    }
                }
                if (record.getTotalPaidIn().compareTo(new BigDecimal(0)) == 0) {
                    record.setPayStatus(PayStatusCode.WAIT.getCode());
                } else if (record.getTotalPaidIn().compareTo(new BigDecimal(0)) > 0 && record.getTotalPaidIn().compareTo(record.getTotalReceivables()) < 0) {
                    record.setPayStatus(PayStatusCode.WAIT_REMAIN.getCode());
                } else if (record.getTotalPaidIn().compareTo(record.getTotalReceivables()) >= 0) {
                    record.setPayStatus(PayStatusCode.FULL_PAYED.getCode());
                }
            }
        }
        PageResponse<SeriesOrderPageDTO> seriesOrderDTOPage = new PageResponse<>(records,
                seriesOrderDTOIPage.getCurrent() == 1,
                seriesOrderDTOIPage.getTotal() <= (seriesOrderDTOIPage.getCurrent() * seriesOrderDTOIPage.getSize()),
                seriesOrderDTOIPage.getTotal(), seriesOrderDTOIPage.getCurrent(),
                seriesOrderDTOIPage.getSize());
        seriesOrderListDTO.setSeriesOrderDTOPage(seriesOrderDTOPage);
        return Result.success(seriesOrderListDTO);
    }

    /**
     * 列表跨店
     */
    @Override
    public PageResponse<SeriesOrderListSpanDTO> listSpan(SeriesOrderListSpanReq req) {
        IPage<SeriesOrderListSpanReq> page = new Page<>(req.getPageNo(), req.getPageSize());
        IPage<SeriesOrderListSpanDTO> seriesOrderDTOIPage = seriesOrderMapper.selectListSpanBySelective(page, req);

        List<SeriesOrderListSpanDTO> records = seriesOrderDTOIPage.getRecords();
        List<Long> listId = new ArrayList<>();
        for (SeriesOrderListSpanDTO record : records) {
            if (record.getScheduleId() != null) {
                listId.add(record.getScheduleId());
            }
        }
        if (records.size() > 0) {
            TripScheduleListIdReq tripScheduleListIdReq = new TripScheduleListIdReq();
            tripScheduleListIdReq.setListId(listId);
            List<TripScheduleListDTO> tripScheduleList = iSeriesTripScheduleService.getTripScheduleList(tripScheduleListIdReq);
            for (SeriesOrderListSpanDTO record : records) {
                //销售人员
                UserDTO createUser = iSysUserService.loadUserInfo(record.getCreateId(), 1);
                if (createUser != null) {
                    record.setCreateName(createUser.getCnSurname() + createUser.getCnName());
                    record.setCreateDept(createUser.getDept());
                }
                if (Objects.equals(record.getPlusTouristType(), PlusTouristTypeCode.DOWN.getCode())) {
                    record.setIsKeep(ISCode.NO.getCode());
                    record.setIsAdd(ISCode.NO.getCode());
                } else if (Objects.equals(record.getPlusTouristType(), PlusTouristTypeCode.KEEP.getCode())) {
                    if (record.getTotalPaidIn().compareTo(new BigDecimal(0)) > 0) {
                        record.setIsKeep(ISCode.NO.getCode());
                    } else {
                        record.setIsKeep(ISCode.YES.getCode());
                    }
                    record.setIsAdd(ISCode.NO.getCode());
                } else if (Objects.equals(record.getPlusTouristType(), PlusTouristTypeCode.ADD.getCode())) {
                    record.setIsKeep(ISCode.NO.getCode());
                    if (Objects.equals(record.getPlaceOrderStatus(), PlaceOrderStatusCode.APPROVAL.getCode())) {
                        record.setIsAdd(PlaceOrderStatusCode.APPROVAL.getCode());
                    } else if (Objects.equals(record.getPlaceOrderStatus(), PlaceOrderStatusCode.APPROVAL_PASS.getCode())) {
                        record.setIsAdd(PlaceOrderStatusCode.APPROVAL_PASS.getCode());
                    } else if (Objects.equals(record.getPlaceOrderStatus(), PlaceOrderStatusCode.APPROVAL_NOT_PASS.getCode())) {
                        record.setIsAdd(PlaceOrderStatusCode.APPROVAL_NOT_PASS.getCode());
                    }
                }
                for (TripScheduleListDTO tripScheduleListDTO : tripScheduleList) {
                    if (Objects.equals(record.getScheduleId(), tripScheduleListDTO.getId())) {
                        if (record.getTotalPaidIn().compareTo(new BigDecimal(0)) == 0) {
                            LocalDateTime orderDateTime = Utils.asLocalDateTime(record.getGmtCreate());
                            if (Objects.equals(record.getIsKeep(), ISCode.YES.getCode())) {
                                if (tripScheduleListDTO.getClearSeatsTime() != null && tripScheduleListDTO.getClearSeatsUnit() != null) {
                                    long clearSeatsTime = Long.parseLong(tripScheduleListDTO.getClearSeatsTime());
                                    if (Objects.equals(tripScheduleListDTO.getClearSeatsUnit(), ClearSeatsUnitCode.MINUTES.getCode())) {
                                        orderDateTime = orderDateTime.plusMinutes(clearSeatsTime);
                                    } else if (Objects.equals(tripScheduleListDTO.getClearSeatsUnit(), ClearSeatsUnitCode.HOUR.getCode())) {
                                        orderDateTime = orderDateTime.plusHours(clearSeatsTime);
                                    }
                                    if (LocalDateTime.now().compareTo(orderDateTime) <= 0) {
                                        record.setRemainingReceivablesRemark(orderDateTime.format(DateTimeFormatter.ofPattern(Utils.HH_mm_ss)) + " 前付款");
                                    }
                                }
                            }
                        } else if (record.getTotalPaidIn().compareTo(new BigDecimal(0)) > 0) {
                            LocalDateTime orderDateTime = Utils.asLocalDateTime(record.getGmtCreate());
                            orderDateTime = orderDateTime.plusDays(tripScheduleListDTO.getDeliveryDays());
                            if (LocalDateTime.now().compareTo(orderDateTime) > 0) {
                                record.setRemainingReceivablesRemark("已超时");
                            }
                        }
                    }
                }
                if (record.getTotalPaidIn().compareTo(new BigDecimal(0)) == 0) {
                    record.setPayStatus(PayStatusCode.WAIT.getCode());
                } else if (record.getTotalPaidIn().compareTo(new BigDecimal(0)) > 0 && record.getTotalPaidIn().compareTo(record.getTotalReceivables()) < 0) {
                    record.setPayStatus(PayStatusCode.WAIT_REMAIN.getCode());
                } else if (record.getTotalPaidIn().compareTo(record.getTotalReceivables()) >= 0) {
                    record.setPayStatus(PayStatusCode.FULL_PAYED.getCode());
                }
            }
        }
        PageResponse<SeriesOrderListSpanDTO> seriesOrderDTOPage = new PageResponse<>(records,
                seriesOrderDTOIPage.getCurrent() == 1,
                seriesOrderDTOIPage.getTotal() <= (seriesOrderDTOIPage.getCurrent() * seriesOrderDTOIPage.getSize()),
                seriesOrderDTOIPage.getTotal(), seriesOrderDTOIPage.getCurrent(),
                seriesOrderDTOIPage.getSize());
        return seriesOrderDTOPage;
    }

    /**
     * 追位确认
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result additionalConfirm(SeriesOrderAdditionalConfirmReq seriesOrderAdditionalConfirmReq) {
        SeriesOrder dbOrder = getById(seriesOrderAdditionalConfirmReq.getId());
        if (!Objects.equals(PlusTouristTypeCode.ADD.getCode(), dbOrder.getPlusTouristType())) {
            return Result.failed(SystemError.SYS_400);
        }
        if (!Objects.equals(PlaceOrderStatusCode.WAIT_CONFIRM.getCode(), dbOrder.getPlaceOrderStatus())) {
            return Result.failed(SeriesOrderErrorCode.STATUS_ERROR);
        }
        SeriesOrder seriesOrder = EntityUtil.copy(seriesOrderAdditionalConfirmReq, SeriesOrder.class);
        seriesOrder.setPlaceOrderStatus(2);


        Result<ApprovalStartDTO> approvalResult = iSysApprovalService.start(SystemBusinessType.OUTBOUND_TRAVEL.getCode(),
                SysApprovalType.CHASE_OUTTRA.getCode(), dbOrder.getId(),
                seriesOrderAdditionalConfirmReq.getUserId(), null, null);
        if (!approvalResult.isSuccess()) {
            throw new BusinessException(SystemError.SYS_500);
        }
        seriesOrder.setApprovalId(approvalResult.getData().getApprovalId());
        boolean update = updateById(seriesOrder);
        if (!update) {
            throw new BusinessException(SystemError.SYS_437);
        }
        //    SeriesOrderDTO seriesOrderDTO = EntityUtil.copy(seriesOrder, SeriesOrderDTO.class);
        return Result.success(seriesOrder.getId());
    }

    /**
     * 留位
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<SeriesOrderDTO> keep(SeriesOrderKeepReq req, TokenUser tokenUser) {
        //获取团期，判断是否能下单
        SeriesTripScheduleDTO tripScheduleDTO = iSeriesTripScheduleService.getTripScheduleId(req.getScheduleId());
        SeriesTripScheduleDataDTO seriesTripScheduleDataDTO = tripScheduleDTO.getSeriesTripScheduleDataDTO();
        SeriesTripScheduleTeamRuleDTO seriesTripScheduleTeamRuleDTO = tripScheduleDTO.getSeriesTripScheduleTeamRuleDTO();

        //++
        if (!Objects.equals(NotISCode.YES.getCode(), seriesTripScheduleTeamRuleDTO.getAllowReservedSeats())) {
            return Result.failed(SeriesOrderErrorCode.KEEP_ORDER_LIMIT);
        }
        //++

        Integer totalPeople = 0;
        //检查游客类型
        BitSet bitSet = new BitSet();
        List<Passenger> passengerList = seriesTripScheduleTeamRuleDTO.getPassenger();

        int touristTypeSize = 0;
        for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
            totalPeople += touristReq.getPeople();
            for (Passenger passenger : passengerList) {
                if (Objects.equals(touristReq.getTouristTypeId(), passenger.getId())) {
                    bitSet.set(touristTypeSize);
                    break;
                }
            }
            touristTypeSize++;
        }
        if (touristTypeSize == bitSet.cardinality()) {
            return Result.failed(SeriesOrderErrorCode.DOWN_ORDER_TOURIST_LIMIT);
        }

        if (seriesTripScheduleTeamRuleDTO.getMaxPeople() - seriesTripScheduleDataDTO.getLockedTouristNum() < 0 ||
                seriesTripScheduleTeamRuleDTO.getReservedSeatsNum() - totalPeople < 0) {
            return Result.failed(SeriesOrderErrorCode.PEOPLE_LIMIT);
        }

        //更新团期 余位
        UpdateSchedulePassengerReq updateSchedulePassengerReq = new UpdateSchedulePassengerReq();
        updateSchedulePassengerReq.setId(req.getScheduleId());
        updateSchedulePassengerReq.setType(UpdateSchedulePassengerTypeCode.KEEP.getCode());
        updateSchedulePassengerReq.setLockedTouristNum(totalPeople);
        Result result = iSeriesTripScheduleService.updateSchedulePassengerReq(updateSchedulePassengerReq, tokenUser);
        if (!result.isSuccess()) {
            return result;
        }

        //占床数
        int occupyBedNum = 0;
        //不占床数
        int notOccupyBedNum = 0;
        for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
            //单房差
            for (Passenger passenger : seriesTripScheduleTeamRuleDTO.getPassenger()) {
                if (Objects.equals(passenger.getMainDataId(), touristReq.getTouristTypeId())) {
                    if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.YES.getCode())) {
                        occupyBedNum = occupyBedNum + touristReq.getPeople();
                    } else if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.NO.getCode())) {
                        notOccupyBedNum = notOccupyBedNum + touristReq.getPeople();
                    }
                }
            }
        }

        //计算最终所需房间数
        Map<String, Integer> roomsResult = SingleRoomUtil.computeRooms(occupyBedNum, notOccupyBedNum,
                req.getRoomNum(),
                (double) seriesTripScheduleTeamRuleDTO.getOccupyBedNum(),
                (double) seriesTripScheduleTeamRuleDTO.getNotOccupyBedNum());
        Integer rooms = roomsResult.get("rooms");
        Integer singleRoomNum = roomsResult.get("singleRoomNum");

        long orderId = SnowflakeIdWorker.nextId();
        LocalDateTime now = LocalDateTime.now();
        SeriesOrder seriesOrder = EntityUtil.copy(req, SeriesOrder.class);

        List<SeriesOrderTouristInfoSaveBatchReq> touristInfoSaveBatchReqList = new ArrayList<>();
        List<SeriesOrderTouristOtherFeeSaveBatchReq> otherFeeSaveBatchReqList = new ArrayList<>();
        List<SeriesOrderTouristFeeAdjustSaveBatchReq> adjustSaveBatchReqList = new ArrayList<>();

        //团费
        BigDecimal orderGroupFee = new BigDecimal(0);
        //应收
        BigDecimal orderTotalReceivables = new BigDecimal(0);
        //实收
        BigDecimal orderTotalPaidIn = new BigDecimal(0);
        //已退款
        BigDecimal orderRefundAmount = new BigDecimal(0);
        //代收费用
        BigDecimal orderCollectionFee = new BigDecimal(0);
        //调整费用
        BigDecimal orderAdjustmentCost = new BigDecimal(0);
        //其他金额
        BigDecimal orderOtherAmount = new BigDecimal(0);
        //已出单据金额
        BigDecimal orderReceiptedAmount = new BigDecimal(0);
        //未收
        BigDecimal orderRemainingReceivables = new BigDecimal(0);

        //人数
        totalPeople = 0;
        if (Objects.equals(tripScheduleDTO.getCostSharingType(), CostSharingType.DEFAULT.getCode())) {
            //默认模板
            TripScheduleDefaultCostDTO tripScheduleDefaultCostDTO = tripScheduleDTO.getTripScheduleDefaultCost();
            SeriesTripScheduleSellingPriceDTO seriesTripScheduleSellingPriceDTO = tripScheduleDefaultCostDTO.getSeriesTripScheduleSellingPriceDTO();
            List<SeriesTripScheduleDefaultCostCollectionDTO> costCollectionList = tripScheduleDefaultCostDTO.getCostCollectionList();
            List<SeriesTripScheduleDefaultFeeAdjustDTO> feeAdjustList = tripScheduleDefaultCostDTO.getFeeAdjustList();

            //单房差
            SeriesTripScheduleDefaultFeeAdjustDTO singleRoomAdjustDTO = null;
            if (CollectionUtils.isNotEmpty(feeAdjustList)) {
                for (SeriesTripScheduleDefaultFeeAdjustDTO seriesTripScheduleDefaultFeeAdjustDTO : feeAdjustList) {
                    if (Objects.equals(seriesTripScheduleDefaultFeeAdjustDTO.getMainDataId(), Constants.SINGLE_ROOM_ID)) {
                        singleRoomAdjustDTO = seriesTripScheduleDefaultFeeAdjustDTO;
                        break;
                    }
                }
            }


            for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
                for (int i = 0; i < touristReq.getPeople(); i++) {
                    long touristId = IdWorker.getId();
                    List<TouristCollectionFeeJson> collectionFeeJsonList = new ArrayList<>();
                    SeriesOrderTouristInfoSaveBatchReq touristInfoSaveBatchReq = new SeriesOrderTouristInfoSaveBatchReq();

                    //团费
                    BigDecimal groupFee = seriesTripScheduleSellingPriceDTO.getGroupCustomerPrice();
                    //获取加幅后的团费
                    //下单类型（0 直客下单，1 代理商下单）
                    if (Objects.equals(req.getOrderType(), 0)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getUserId());
                    } else if (Objects.equals(req.getOrderType(), 1)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getAgentId());
                    }
                    //应收
                    BigDecimal totalReceivables = new BigDecimal(0);
                    //实收
                    BigDecimal totalPaidIn = new BigDecimal(0);
                    //已退款
                    BigDecimal refundAmount = new BigDecimal(0);
                    //代收费用
                    BigDecimal collectionFee = new BigDecimal(0);
                    //调整费用
                    BigDecimal adjustmentCost = new BigDecimal(0);
                    //其他金额
                    BigDecimal otherAmount = new BigDecimal(0);
                    //已出单据金额
                    BigDecimal receiptedAmount = new BigDecimal(0);
                    //未收
                    BigDecimal remainingReceivables = new BigDecimal(0);

                    if (CollectionUtils.isNotEmpty(costCollectionList)) {
                        for (SeriesTripScheduleDefaultCostCollectionDTO seriesTripScheduleDefaultCostCollectionDTO : costCollectionList) {
                            SeriesTripScheduleDefaultCostTouristTypeDTO selectTypeDTO = null;

                            //判断代收费用中是否有相同游客类型的代收费用
                            for (SeriesTripScheduleDefaultCostTouristTypeDTO typeDTO : seriesTripScheduleDefaultCostCollectionDTO.getCostCollectionTypeList()) {
                                if (Objects.equals(typeDTO.getTouristTypeId(), touristReq.getTouristTypeId())) {
                                    selectTypeDTO = typeDTO;
                                    break;
                                }
                            }

                            if (selectTypeDTO == null) {
                                continue;
                            }

                            TouristCollectionFeeJson collectionFeeJson = new TouristCollectionFeeJson();
                            collectionFeeJson.setProjectName(seriesTripScheduleDefaultCostCollectionDTO.getProjectName());
                            collectionFeeJson.setMainDataId(seriesTripScheduleDefaultCostCollectionDTO.getMainDataId());
                            collectionFeeJson.setAdjustType(1);
                            collectionFeeJson.setTotalAmount(selectTypeDTO.getTotalAmount().multiply(new BigDecimal(seriesTripScheduleDefaultCostCollectionDTO.getExchangeRate())).setScale(2, BigDecimal.ROUND_HALF_UP));
                            collectionFeeJsonList.add(collectionFeeJson);

                            //如有,将行程代收费保存用到(订单)代收费用
                            /*SeriesOrderTouristOtherFeeSaveBatchReq otherFeeSaveBatchReq = new SeriesOrderTouristOtherFeeSaveBatchReq();
                            otherFeeSaveBatchReq.setFeeType(SeriesOrderTouristOtherFeeFeeTypeCode.COLLECTION.getCode());
                            otherFeeSaveBatchReq.setOrderId(orderId);
                            otherFeeSaveBatchReq.setTouristId(touristId);
                            otherFeeSaveBatchReq.setFeeName(seriesTripScheduleDefaultCostCollectionDTO.getProjectName());
                            otherFeeSaveBatchReq.setRelationId(seriesTripScheduleDefaultCostCollectionDTO.getId());
                            otherFeeSaveBatchReq.setAmount(selectTypeDTO.getTotalAmount());
                            otherFeeSaveBatchReq.setGmtCreate(now);
                            otherFeeSaveBatchReq.setGmtModified(now);
                            otherFeeSaveBatchReq.setCreateId(req.getUserId());
                            otherFeeSaveBatchReq.setModifiedId(req.getUserId());
                            otherFeeSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                            otherFeeSaveBatchReqList.add(otherFeeSaveBatchReq);*/

                            //累计代收费用
                            collectionFee = collectionFee.add(selectTypeDTO.getTotalAmount());
                        }
                    }

                    if (collectionFeeJsonList.size() > 0) {
                        touristInfoSaveBatchReq.setCollectionFeeJson(JSON.toJSONString(collectionFeeJsonList));
                    }
                    //其他费用

                    //调整费用
                    if (singleRoomAdjustDTO != null && singleRoomNum > 0) {
                        SeriesOrderTouristFeeAdjustSaveBatchReq seriesOrderTouristFeeAdjust = new SeriesOrderTouristFeeAdjustSaveBatchReq();
                        seriesOrderTouristFeeAdjust.setRelationId(singleRoomAdjustDTO.getId());
                        seriesOrderTouristFeeAdjust.setAmount(singleRoomAdjustDTO.getCostAmount());
                        seriesOrderTouristFeeAdjust.setPlusType(singleRoomAdjustDTO.getAdjustType());
                        seriesOrderTouristFeeAdjust.setName(singleRoomAdjustDTO.getProjectName());
                        seriesOrderTouristFeeAdjust.setTouristId(touristId);
                        seriesOrderTouristFeeAdjust.setAdjustType(AdjustTypeCode.ADJUST.getCode());
                        seriesOrderTouristFeeAdjust.setOrderId(orderId);
                        seriesOrderTouristFeeAdjust.setUserId(req.getUserId());
                        adjustSaveBatchReqList.add(seriesOrderTouristFeeAdjust);

                        singleRoomNum--;

                        //累计调整费用
                        if (Objects.equals(singleRoomAdjustDTO.getAdjustType(), PlusTypeCode.PLUS.getCode())) {
                            adjustmentCost = adjustmentCost.add(singleRoomAdjustDTO.getCostAmount());
                        } else if (Objects.equals(singleRoomAdjustDTO.getAdjustType(), PlusTypeCode.SUBTRACT.getCode())) {
                            adjustmentCost = adjustmentCost.subtract(singleRoomAdjustDTO.getCostAmount());
                        }
                    }

                    //应收=团费+代收+调整+其他
                    totalReceivables = ((groupFee.add(collectionFee)).add(adjustmentCost)).add(otherAmount);
                    //未收=应收-实收
                    remainingReceivables = totalReceivables.subtract(totalPaidIn);

                    touristInfoSaveBatchReq.setId(touristId);
                    touristInfoSaveBatchReq.setOrderId(orderId);
                    touristInfoSaveBatchReq.setScheduleId(seriesOrder.getScheduleId());
                    touristInfoSaveBatchReq.setMainDataId(touristReq.getTouristTypeId());
                    touristInfoSaveBatchReq.setTouristTypeName(touristReq.getTouristTypeName());
                    touristInfoSaveBatchReq.setPayStatus(PayStatusCode.WAIT.getCode());
                    touristInfoSaveBatchReq.setNoshow(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setLockStatus(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                    touristInfoSaveBatchReq.setGmtCreate(now);
                    touristInfoSaveBatchReq.setGmtModified(now);
                    touristInfoSaveBatchReq.setCreateId(req.getUserId());
                    touristInfoSaveBatchReq.setModifiedId(req.getUserId());
                    touristInfoSaveBatchReq.setIsFullInfo(ISCode.NO.getCode());
                    //订单统计
                    touristInfoSaveBatchReq.setGroupFee(groupFee);
                    touristInfoSaveBatchReq.setTotalReceivables(totalReceivables);
                    touristInfoSaveBatchReq.setTotalPaidIn(totalPaidIn);
                    touristInfoSaveBatchReq.setRefundAmount(refundAmount);
                    touristInfoSaveBatchReq.setCollectionFee(collectionFee);
                    touristInfoSaveBatchReq.setAdjustmentCost(adjustmentCost);
                    touristInfoSaveBatchReq.setOtherAmount(otherAmount);
                    touristInfoSaveBatchReq.setReceiptedAmount(receiptedAmount);
                    touristInfoSaveBatchReq.setRemainingReceivables(remainingReceivables);
                    touristInfoSaveBatchReq.setIsReceiptCalculated(ISCode.NO.getCode());
                    touristInfoSaveBatchReq.setBuyInsurance(ISCode.NO.getCode());
                    touristInfoSaveBatchReqList.add(touristInfoSaveBatchReq);

                    //人数
                    totalPeople++;
                    //团费
                    orderGroupFee = orderGroupFee.add(groupFee);
                    //应收
                    orderTotalReceivables = orderTotalReceivables.add(totalReceivables);
                    //实收
                    orderTotalPaidIn = orderTotalPaidIn.add(totalPaidIn);
                    //已退款
                    orderRefundAmount = orderRefundAmount.add(refundAmount);
                    //代收费用
                    orderCollectionFee = orderCollectionFee.add(collectionFee);
                    //调整费用
                    orderAdjustmentCost = orderAdjustmentCost.add(adjustmentCost);
                    //其他金额
                    orderOtherAmount = orderOtherAmount.add(otherAmount);
                    //已出单据金额
                    orderReceiptedAmount = orderReceiptedAmount.add(receiptedAmount);
                    //未收
                    orderRemainingReceivables = orderRemainingReceivables.add(remainingReceivables);

                }
            }
        } else if (Objects.equals(tripScheduleDTO.getCostSharingType(), CostSharingType.CUSTOM.getCode())) {
            //自定义
            TripCustomCostReq tripCustomCostReq = tripScheduleDTO.getTripCustomCostReq();
            List<TripCustomSalePriceReq> customSalePriceList = tripCustomCostReq.getCustomSalePriceList();
            ;
            List<SeriesTripDefaultCostCollectionReq> customCostCollectionList = tripCustomCostReq.getCostCollectionList();
            List<SeriesTripCustomFeeAdjustReq> customFeeAdjustList = tripCustomCostReq.getFeeAdjustList();
            for (SeriesOrderTouristReq touristReq : req.getTouristList()) {
                //团费
                TripCustomSalePriceReq selectTripCustomSalePriceReq = null;
                A:
                if (CollectionUtils.isNotEmpty(customSalePriceList)) {
                    for (TripCustomSalePriceReq tripCustomSalePriceReq : customSalePriceList) {
                        if (Objects.equals(tripCustomSalePriceReq.getMainDataId(), touristReq.getTouristTypeId())) {
                            if (Objects.equals(tripCustomSalePriceReq.getDateType(), DataType.WEEK.getCode())) {
                                for (Integer checkWeekDay : tripCustomSalePriceReq.getCheckWeekDays()) {
                                    if (Objects.equals(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue(), checkWeekDay)) {
                                        selectTripCustomSalePriceReq = tripCustomSalePriceReq;
                                        break A;
                                    }
                                }
                            } else if (Objects.equals(tripCustomSalePriceReq.getDateType(), DataType.DATE.getCode())) {
                                if (tripScheduleDTO.getDepartureDate().compareTo(tripCustomSalePriceReq.getDateBegin()) >= 0
                                        && tripScheduleDTO.getDepartureDate().compareTo(tripCustomSalePriceReq.getDateEnd()) <= 0) {
                                    selectTripCustomSalePriceReq = tripCustomSalePriceReq;
                                    break A;
                                }
                            }
                        }
                    }
                }

                if (selectTripCustomSalePriceReq == null) {
                    throw new BusinessException(SystemError.SYS_411);
                }

                //单房差
                SeriesTripCustomFeeAdjustReq singleRoomCustomFeeAdjustReq = null;
                CustomCostReq singleRoomCustomCostReq = null;
                B:
                if (CollectionUtils.isNotEmpty(customFeeAdjustList)) {
                    for (SeriesTripCustomFeeAdjustReq seriesTripCustomFeeAdjustReq : customFeeAdjustList) {
                        if (Objects.equals(seriesTripCustomFeeAdjustReq.getMainDataId(), Constants.SINGLE_ROOM_ID)) {
                            for (CustomCostReq customCostReq : seriesTripCustomFeeAdjustReq.getCustomCostList()) {
                                if (Objects.equals(customCostReq.getMainDataId(), touristReq.getTouristTypeId())) {
                                    if (Objects.equals(customCostReq.getDateType(), DataType.WEEK.getCode())) {
                                        for (Integer checkWeekDay : customCostReq.getCheckWeekDays()) {
                                            if (Objects.equals(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue(), checkWeekDay)) {
                                                singleRoomCustomFeeAdjustReq = seriesTripCustomFeeAdjustReq;
                                                singleRoomCustomCostReq = customCostReq;
                                                break B;
                                            }
                                        }
                                    } else if (Objects.equals(customCostReq.getDateType(), DataType.DATE.getCode())) {
                                        if (tripScheduleDTO.getDepartureDate().compareTo(customCostReq.getDateBegin()) >= 0
                                                && tripScheduleDTO.getDepartureDate().compareTo(customCostReq.getDateEnd()) <= 0) {
                                            singleRoomCustomFeeAdjustReq = seriesTripCustomFeeAdjustReq;
                                            singleRoomCustomCostReq = customCostReq;
                                            break B;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }


                for (int i = 0; i < touristReq.getPeople(); i++) {
                    long touristId = IdWorker.getId();
                    List<TouristCollectionFeeJson> collectionFeeJsonList = new ArrayList<>();
                    SeriesOrderTouristInfoSaveBatchReq touristInfoSaveBatchReq = new SeriesOrderTouristInfoSaveBatchReq();

                    //团费
                    BigDecimal groupFee = selectTripCustomSalePriceReq.getGroupCustomerPrice();
                    //获取加幅后的团费
                    //下单类型（0 直客下单，1 代理商下单）
                    if (Objects.equals(req.getOrderType(), 0)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getUserId());
                    } else if (Objects.equals(req.getOrderType(), 1)) {
                        groupFee = iSeriesTripScheduleService.getAddGroupFee(req.getOrderType(), req.getScheduleId(), groupFee, req.getAgentId());
                    }
                    //应收
                    BigDecimal totalReceivables = new BigDecimal(0);
                    //实收
                    BigDecimal totalPaidIn = new BigDecimal(0);
                    //已退款
                    BigDecimal refundAmount = new BigDecimal(0);
                    //代收费用
                    BigDecimal collectionFee = new BigDecimal(0);
                    //调整费用
                    BigDecimal adjustmentCost = new BigDecimal(0);
                    //其他金额
                    BigDecimal otherAmount = new BigDecimal(0);
                    //已出单据金额
                    BigDecimal receiptedAmount = new BigDecimal(0);
                    //未收
                    BigDecimal remainingReceivables = new BigDecimal(0);

                    if (CollectionUtils.isNotEmpty(customCostCollectionList)) {
                        for (SeriesTripDefaultCostCollectionReq seriesTripDefaultCostCollectionReq : customCostCollectionList) {
                            SeriesTripDefaultCostCollectionTypeReq selectTypeDTO = null;

                            //判断代收费用中是否有相同游客类型的代收费用
                            for (SeriesTripDefaultCostCollectionTypeReq typeDTO : seriesTripDefaultCostCollectionReq.getCostCollectionTypeList()) {
                                if (Objects.equals(typeDTO.getTouristTypeId(), touristReq.getTouristTypeId())) {
                                    selectTypeDTO = typeDTO;
                                    break;
                                }
                            }

                            if (selectTypeDTO == null) {
                                continue;
                            }

                            TouristCollectionFeeJson collectionFeeJson = new TouristCollectionFeeJson();
                            collectionFeeJson.setProjectName(seriesTripDefaultCostCollectionReq.getProjectName());
                            collectionFeeJson.setMainDataId(seriesTripDefaultCostCollectionReq.getMainDataId());
                            collectionFeeJson.setAdjustType(1);
                            collectionFeeJson.setTotalAmount(selectTypeDTO.getTotalAmount().multiply(new BigDecimal(seriesTripDefaultCostCollectionReq.getExchangeRate())).setScale(2, BigDecimal.ROUND_HALF_UP));
                            collectionFeeJsonList.add(collectionFeeJson);

                            //如有,将行程代收费保存用到(订单)代收费用
                            /*SeriesOrderTouristOtherFeeSaveBatchReq otherFeeSaveBatchReq = new SeriesOrderTouristOtherFeeSaveBatchReq();
                            otherFeeSaveBatchReq.setFeeType(SeriesOrderTouristOtherFeeFeeTypeCode.COLLECTION.getCode());
                            otherFeeSaveBatchReq.setOrderId(orderId);
                            otherFeeSaveBatchReq.setTouristId(touristId);
                            otherFeeSaveBatchReq.setFeeName(seriesTripDefaultCostCollectionReq.getProjectName());
                            otherFeeSaveBatchReq.setRelationId(seriesTripDefaultCostCollectionReq.getId());
                            otherFeeSaveBatchReq.setAmount(selectTypeDTO.getTotalAmount());
                            otherFeeSaveBatchReq.setGmtCreate(now);
                            otherFeeSaveBatchReq.setGmtModified(now);
                            otherFeeSaveBatchReq.setCreateId(req.getUserId());
                            otherFeeSaveBatchReq.setModifiedId(req.getUserId());
                            otherFeeSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                            otherFeeSaveBatchReqList.add(otherFeeSaveBatchReq);*/

                            //累计代收费用
                            collectionFee = collectionFee.add(selectTypeDTO.getTotalAmount());
                        }
                    }

                    if (collectionFeeJsonList.size() > 0) {
                        touristInfoSaveBatchReq.setCollectionFeeJson(JSON.toJSONString(collectionFeeJsonList));
                    }
                    //其他费用

                    //调整费用
                    if (singleRoomCustomFeeAdjustReq != null && singleRoomCustomCostReq != null &&
                            singleRoomNum > 0) {
                        SeriesOrderTouristFeeAdjustSaveBatchReq seriesOrderTouristFeeAdjust = new SeriesOrderTouristFeeAdjustSaveBatchReq();
                        seriesOrderTouristFeeAdjust.setRelationId(singleRoomCustomFeeAdjustReq.getId());
                        seriesOrderTouristFeeAdjust.setAmount(singleRoomCustomCostReq.getPrice());
                        seriesOrderTouristFeeAdjust.setPlusType(singleRoomCustomFeeAdjustReq.getAdjustType());
                        seriesOrderTouristFeeAdjust.setName(singleRoomCustomFeeAdjustReq.getProjectName());
                        seriesOrderTouristFeeAdjust.setTouristId(touristId);
                        seriesOrderTouristFeeAdjust.setAdjustType(AdjustTypeCode.ADJUST.getCode());
                        seriesOrderTouristFeeAdjust.setOrderId(orderId);
                        seriesOrderTouristFeeAdjust.setUserId(req.getUserId());
                        adjustSaveBatchReqList.add(seriesOrderTouristFeeAdjust);

                        singleRoomNum--;

                        //累计调整费用
                        if (Objects.equals(singleRoomCustomFeeAdjustReq.getAdjustType(), PlusTypeCode.PLUS.getCode())) {
                            adjustmentCost = adjustmentCost.add(singleRoomCustomCostReq.getPrice());
                        } else if (Objects.equals(singleRoomCustomFeeAdjustReq.getAdjustType(), PlusTypeCode.SUBTRACT.getCode())) {
                            adjustmentCost = adjustmentCost.subtract(singleRoomCustomCostReq.getPrice());
                        }
                    }

                    //应收=团费+代收+调整+其他
                    totalReceivables = ((groupFee.add(collectionFee)).add(adjustmentCost)).add(otherAmount);
                    //未收=应收-实收
                    remainingReceivables = totalReceivables.subtract(totalPaidIn);

                    touristInfoSaveBatchReq.setId(touristId);
                    touristInfoSaveBatchReq.setOrderId(orderId);
                    touristInfoSaveBatchReq.setScheduleId(seriesOrder.getScheduleId());
                    touristInfoSaveBatchReq.setMainDataId(touristReq.getTouristTypeId());
                    touristInfoSaveBatchReq.setPayStatus(PayStatusCode.WAIT.getCode());
                    touristInfoSaveBatchReq.setNoshow(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setLockStatus(LockStatusCode.NO.getCode());
                    touristInfoSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                    touristInfoSaveBatchReq.setGmtCreate(now);
                    touristInfoSaveBatchReq.setGmtModified(now);
                    touristInfoSaveBatchReq.setCreateId(req.getUserId());
                    touristInfoSaveBatchReq.setModifiedId(req.getUserId());
                    touristInfoSaveBatchReq.setIsFullInfo(ISCode.NO.getCode());
                    //订单统计
                    touristInfoSaveBatchReq.setGroupFee(groupFee);
                    touristInfoSaveBatchReq.setTotalReceivables(totalReceivables);
                    touristInfoSaveBatchReq.setTotalPaidIn(totalPaidIn);
                    touristInfoSaveBatchReq.setRefundAmount(refundAmount);
                    touristInfoSaveBatchReq.setCollectionFee(collectionFee);
                    touristInfoSaveBatchReq.setAdjustmentCost(adjustmentCost);
                    touristInfoSaveBatchReq.setOtherAmount(otherAmount);
                    touristInfoSaveBatchReq.setReceiptedAmount(receiptedAmount);
                    touristInfoSaveBatchReq.setRemainingReceivables(remainingReceivables);
                    touristInfoSaveBatchReq.setIsReceiptCalculated(ISCode.NO.getCode());
                    touristInfoSaveBatchReq.setBuyInsurance(ISCode.NO.getCode());
                    touristInfoSaveBatchReqList.add(touristInfoSaveBatchReq);

                    //人数
                    totalPeople++;
                    //团费
                    orderGroupFee = orderGroupFee.add(groupFee);
                    //应收
                    orderTotalReceivables = orderTotalReceivables.add(totalReceivables);
                    //实收
                    orderTotalPaidIn = orderTotalPaidIn.add(totalPaidIn);
                    //已退款
                    orderRefundAmount = orderRefundAmount.add(refundAmount);
                    //代收费用
                    orderCollectionFee = orderCollectionFee.add(collectionFee);
                    //调整费用
                    orderAdjustmentCost = orderAdjustmentCost.add(adjustmentCost);
                    //其他金额
                    orderOtherAmount = orderOtherAmount.add(otherAmount);
                    //已出单据金额
                    orderReceiptedAmount = orderReceiptedAmount.add(receiptedAmount);
                    //未收
                    orderRemainingReceivables = orderRemainingReceivables.add(remainingReceivables);

                }
            }
        }

        if (touristInfoSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristInfoService.saveBatch(touristInfoSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_408);
            }
        }
        if (otherFeeSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristOtherFeeService.saveBatch(otherFeeSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_408);
            }
        }
        if (adjustSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristFeeAdjustService.saveBatch(adjustSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_408);
            }
        }

        seriesOrder.setId(orderId);
        seriesOrder.setSalesmanId(req.getUserId());
        seriesOrder.setOrderNumber(getOrderNumber(req.getUserId()));
        seriesOrder.setPlusTouristType(PlusTouristTypeCode.KEEP.getCode());//++
        seriesOrder.setPlaceOrderStatus(PlaceOrderStatusCode.WAIT_CONFIRM.getCode());
        seriesOrder.setIsDeleted(IsDeletedCode.NO.getCode());
        seriesOrder.setGmtCreate(now);
        seriesOrder.setGmtModified(now);
        seriesOrder.setTotalPeople(totalPeople);
        seriesOrder.setTotalPrice(orderGroupFee);
        seriesOrder.setCreateId(req.getUserId());
        seriesOrder.setModifiedId(req.getUserId());
        if (Objects.equals(req.getOrderType(), OrderTypeCode.CLIENT.getCode())) {
            seriesOrder.setOrderSource(OrderSourceCode.CPM.getCode());
        } else if (Objects.equals(req.getOrderType(), OrderTypeCode.PROXY.getCode())) {
            seriesOrder.setOrderSource(OrderSourceCode.CPM_PROXY.getCode());
        }
        seriesOrder.setTripId(seriesTripScheduleDataDTO.getTripId());
        seriesOrder.setTripTitle(seriesTripScheduleDataDTO.getTitle());
        seriesOrder.setScheduleNumber(tripScheduleDTO.getTripNumber());
        seriesOrder.setDepartDate(tripScheduleDTO.getDepartureDate());
        seriesOrder.setScheduleStatus(tripScheduleDTO.getScheduleStatus());
        boolean save = save(seriesOrder);

        //统计
        SeriesOrderAmountStatistics statistics = new SeriesOrderAmountStatistics();
        statistics.setScheduleId(req.getScheduleId());
        statistics.setOrderId(orderId);
        statistics.setTotalTourFee(orderGroupFee);
        statistics.setTotalReceivables(orderTotalReceivables);
        statistics.setTotalPaidIn(orderTotalPaidIn);
        statistics.setRefundAmount(orderRefundAmount);
        statistics.setCollectionFee(orderCollectionFee);
        statistics.setAdjustmentCost(orderAdjustmentCost);
        statistics.setOtherAmount(orderOtherAmount);
        statistics.setReceiptedAmount(orderReceiptedAmount);
        statistics.setRemainingReceivables(orderRemainingReceivables);
        int insert = seriesOrderAmountStatisticsMapper.insert(statistics);

        if (!save || insert <= 0) {
            throw new BusinessException(SystemError.SYS_408);
        }

        /*JSONObject jsonObject = new JSONObject();
        jsonObject.put("orderId", seriesOrder.getId());
        OhMyClient taskClient = new OhMyClient(domain, appName, password);
        ResultDTO<Long> resultTask = taskClient.runJob(jobIdCloseOccupy, jsonObject.toJSONString(), Constants.DELAY_MS);
        if (!resultTask.isSuccess()) {
            throw new BusinessException(SystemError.SYS_500);
        }
        redisTemplate.opsForValue().set(RedisConstants.ORDER_TOUR_CLOSE_OCCUPY_ID_KEY + seriesOrder.getId(), resultTask.getData(), Constants.DELAY_MS, TimeUnit.MILLISECONDS);
*/
        SeriesOrderDTO seriesOrderDTO = EntityUtil.copy(seriesOrder, SeriesOrderDTO.class);
        return Result.success(seriesOrderDTO);
    }

    /**
     * 留位确认
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<SeriesOrderDTO> keepConfirm(SeriesOrderKeepConfirmReq seriesOrderKeepConfirmReq) {
        SeriesOrder dbOrder = getById(seriesOrderKeepConfirmReq.getId());
        if (!Objects.equals(PlusTouristTypeCode.KEEP.getCode(), dbOrder.getPlusTouristType())) {
            return Result.failed(SystemError.SYS_400);
        }
        if (!Objects.equals(PlaceOrderStatusCode.WAIT_CONFIRM.getCode(), dbOrder.getPlaceOrderStatus())) {
            return Result.failed(SeriesOrderErrorCode.STATUS_ERROR);
        }
        SeriesOrder seriesOrder = EntityUtil.copy(seriesOrderKeepConfirmReq, SeriesOrder.class);
        seriesOrder.setPlaceOrderStatus(PlaceOrderStatusCode.CONFIRM.getCode());
        updateById(seriesOrder);

        //关闭
        Long instanceId = (Long) redisTemplate.opsForValue().get(RedisConstants.ORDER_TOUR_CLOSE_OCCUPY_ID_KEY + dbOrder.getId());
        if (instanceId != null) {
            /*OhMyClient taskClient = new OhMyClient(domain, appName, password);
            ResultDTO<Void> resultTask = taskClient.cancelInstance(instanceId);

            if (!resultTask.isSuccess()) {
                // 取消任务执行成功
                log.info("取消【关闭占位】任务,订单id[{}],任务实例id[{}]", dbOrder.getId(), instanceId);
            }*/
        }

        SeriesTripScheduleDTO tripScheduleDTO = iSeriesTripScheduleService.getTripScheduleId(dbOrder.getScheduleId());
        SeriesTripScheduleTeamRuleDTO seriesTripScheduleTeamRuleDTO = tripScheduleDTO.getSeriesTripScheduleTeamRuleDTO();

        long clearSeatsTime = Long.parseLong(seriesTripScheduleTeamRuleDTO.getClearSeatsTime());
        if (Objects.equals(seriesTripScheduleTeamRuleDTO.getClearSeatsUnit(), ClearSeatsUnitCode.MINUTES.getCode())) {
            clearSeatsTime = 1000 * 60 * clearSeatsTime;
        } else if (Objects.equals(seriesTripScheduleTeamRuleDTO.getClearSeatsUnit(), ClearSeatsUnitCode.HOUR.getCode())) {
            clearSeatsTime = 1000 * 60 * 60 * clearSeatsTime;
        }

        /*JSONObject jsonObject = new JSONObject();
        jsonObject.put("orderId", seriesOrder.getId());
        OhMyClient taskClient2 = new OhMyClient(domain, appName, password);
        ResultDTO<Long> resultTask2 = taskClient2.runJob(jobIdCloseKeep, jsonObject.toJSONString(), clearSeatsTime);
        if (!resultTask2.isSuccess()) {
            throw new BusinessException(SystemError.SYS_500);
        }
        redisTemplate.opsForValue().set(RedisConstants.ORDER_TOUR_CLOSE_KEEP_ID_KEY + seriesOrder.getId(), resultTask2.getData(), Constants.DELAY_MS, TimeUnit.MILLISECONDS);
*/
        SeriesOrderDTO seriesOrderDTO = EntityUtil.copy(seriesOrder, SeriesOrderDTO.class);
        return Result.success(seriesOrderDTO);
    }

    /**
     * 详情
     */
    @Override
    public Result<SeriesOrderDetailDTO> detail(SeriesOrderDetailReq req) {
        SeriesOrderDetailDTO dto = seriesOrderMapper.selectDetailBySelective(req);
        if (dto != null) {
            if (Objects.equals(dto.getIsDeleted(), IsDeletedCode.YES.getCode())) {
                return Result.failed(SystemError.SYS_423);
            }
        }
        return Result.success(dto);
    }

    /**
     * 取消
     */
    @Override
    public Result cancel(SeriesOrderCancelReq req) {
        QueryWrapper<SeriesOrderAmountStatistics> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SeriesOrderAmountStatistics::getOrderId, req.getId());
        SeriesOrderAmountStatistics dbStatistics = seriesOrderAmountStatisticsMapper.selectOne(queryWrapper);

//        SeriesOrder updateObject = EntityUtil.copy(req, SeriesOrder.class);
        SeriesOrder dbOrder = getById(req.getId());
        if (Objects.equals(dbOrder.getPlusTouristType(), PlusTouristTypeCode.DOWN.getCode())) {
            if (dbStatistics.getTotalPaidIn().compareTo(new BigDecimal(0)) > 0) {
                return Result.failed(SeriesOrderErrorCode.CANCEL_ORDER_LIMIT);
            }
            UpdateScheduleNumReq updateScheduleNumReq = new UpdateScheduleNumReq();
            updateScheduleNumReq.setId(dbOrder.getScheduleId());
            updateScheduleNumReq.setNum(dbOrder.getTotalPeople());
            Result result = iSeriesTripScheduleService.updateScheduleNum(updateScheduleNumReq);
            if (!result.isSuccess()) {
                throw new BusinessException(SystemError.SYS_500);
            }
            dbOrder.setIsUnlock(1);
//            updateObject.setIsDeleted(IsDeletedCode.YES.getCode());
        } else if (Objects.equals(dbOrder.getPlusTouristType(), PlusTouristTypeCode.KEEP.getCode())) {
            if (dbStatistics.getTotalPaidIn().compareTo(new BigDecimal(0)) > 0) {
                return Result.failed(SeriesOrderErrorCode.CANCEL_ORDER_LIMIT);
            }
            Long instanceId = (Long) redisTemplate.opsForValue().get(RedisConstants.ORDER_TOUR_CLOSE_KEEP_ID_KEY + dbOrder.getId());
            if (instanceId != null) {
                /*OhMyClient taskClient = new OhMyClient(domain, appName, password);
                ResultDTO<Void> resultTask = taskClient.cancelInstance(instanceId);

                if (!resultTask.isSuccess()) {
                    // 取消任务执行成功
                    log.info("取消【关闭留位】任务,订单id[{}],任务实例id[{}]", dbOrder.getId(), instanceId);
                }*/
            }
            UpdateScheduleNumReq updateScheduleNumReq = new UpdateScheduleNumReq();
            updateScheduleNumReq.setId(dbOrder.getScheduleId());
            updateScheduleNumReq.setNum(dbOrder.getTotalPeople());
            Result result = iSeriesTripScheduleService.updateScheduleNum(updateScheduleNumReq);
            if (!result.isSuccess()) {
                return Result.failed(SystemError.SYS_500);
            }
            dbOrder.setIsUnlock(1);
//            updateObject.setIsDeleted(IsDeletedCode.YES.getCode());
        } else if (Objects.equals(dbOrder.getPlusTouristType(), PlusTouristTypeCode.ADD.getCode())) {
            if (Objects.equals(dbOrder.getPlaceOrderStatus(), PlaceOrderStatusCode.APPROVAL.getCode())) {
                return Result.failed(SeriesOrderErrorCode.CANCEL_ORDER_ERROR);
            } else if (Objects.equals(dbOrder.getPlaceOrderStatus(), PlaceOrderStatusCode.APPROVAL_NOT_PASS.getCode())) {
//                updateObject.setIsDeleted(IsDeletedCode.YES.getCode());
            } else if (Objects.equals(dbOrder.getPlaceOrderStatus(), PlaceOrderStatusCode.APPROVAL_PASS.getCode())) {
                if (dbStatistics.getTotalPaidIn().compareTo(new BigDecimal(0)) > 0) {
                    return Result.failed(SeriesOrderErrorCode.CANCEL_ORDER_LIMIT);
                }
//                updateObject.setIsDeleted(IsDeletedCode.YES.getCode());
            }
        }
//        updateById(updateObject);

        //删除订单
        SeriesOrder entity = newDeleteEntityUserId(SeriesOrder.class, req.getId(), req.getUserId());
        seriesOrderMapper.assertUpdateById(entity);

        //删除旅客名单
        SeriesOrderTouristInfo touristInfo = newDeleteEntityUserId(SeriesOrderTouristInfo.class, null, req.getUserId());
        seriesOrderTouristInfoMapper.updateByKey(touristInfo, "order_id", req.getId());

        return Result.success(dbOrder.getId());
    }

    /**
     * 游客排序
     *
     * @param touristList
     * @return
     */
    public List<SeriesOrderTouristReq> touristListSort(List<SeriesOrderTouristReq> touristList) {
        List<SeriesOrderTouristReq> list = null;
        if (null != touristList && touristList.size() > 0) {
            //list = touristList.stream().sorted(Comparator.comparing(SeriesOrderTouristReq::getSort)).collect(Collectors.toList());
        }
        return touristList;
    }

    /**
     * 计算单房差-B端
     */
    @Override//TODO
    public Result<SeriesOrderCalculationDTO> calculation(SeriesOrderCalculationReq req) {
        SeriesTripScheduleDTO tripScheduleDTO = iSeriesTripScheduleService.getTripScheduleId(req.getScheduleId());
        SeriesTripScheduleDataDTO seriesTripScheduleDataDTO = tripScheduleDTO.getSeriesTripScheduleDataDTO();
        SeriesTripScheduleTeamRuleDTO seriesTripScheduleTeamRuleDTO = tripScheduleDTO.getSeriesTripScheduleTeamRuleDTO();
        if (org.springframework.util.StringUtils.isEmpty(seriesTripScheduleDataDTO.getNightDays())) {
            throw new BusinessException(SystemError.TOUR_ORDER_30037);
        }
        SeriesOrderCalculationDTO dto = new SeriesOrderCalculationDTO();
        List<SeriesOrderCalculationItemDTO> groupFeeItemDTOList = new ArrayList<>();
        List<SeriesOrderCalculationItemDTO> singleRoomItemList = new ArrayList<>();
        List<SeriesOrderCalculationItemDTO> collectionItemDTOList = new ArrayList<>();

        BigDecimal totalAmount = new BigDecimal(0);
        List<SeriesOrderTouristReq> touristList = touristListSort(req.getTouristList());
        if (Objects.equals(tripScheduleDTO.getCostSharingType(), CostSharingType.DEFAULT.getCode())) {
            //默认模板
            TripScheduleDefaultCostDTO tripScheduleDefaultCostDTO = tripScheduleDTO.getTripScheduleDefaultCost();
            SeriesTripScheduleSellingPriceDTO seriesTripScheduleSellingPriceDTO = tripScheduleDefaultCostDTO.getSeriesTripScheduleSellingPriceDTO();
            List<SeriesTripScheduleDefaultCostCollectionDTO> costCollectionList = tripScheduleDefaultCostDTO.getCostCollectionList();
            List<SeriesTripScheduleDefaultFeeAdjustDTO> feeAdjustList = tripScheduleDefaultCostDTO.getFeeAdjustList();

            //占床数
            int occupyBedNum = 0;
            //不占床数
            int notOccupyBedNum = 0;
            for (SeriesOrderTouristReq touristReq : touristList) {
                SeriesOrderCalculationItemDTO groupFeeItem = new SeriesOrderCalculationItemDTO();
                groupFeeItem.setProjectName(touristReq.getTouristTypeName());
                //TODO 团费直客价+加幅价格
                BigDecimal price = iSeriesTripScheduleService.calcSalePriceInfoHandle(1, tripScheduleDTO.getId(), req.getUserId(), seriesTripScheduleSellingPriceDTO.getGroupCustomerPrice());
                groupFeeItem.setAmount(price);
                groupFeeItem.setQuantity(touristReq.getPeople());
                groupFeeItem.setTotalAmount(price.multiply(new BigDecimal(touristReq.getPeople())));
                groupFeeItemDTOList.add(groupFeeItem);

                totalAmount = totalAmount.add(groupFeeItem.getTotalAmount());

                //单房差
                for (Passenger passenger : seriesTripScheduleTeamRuleDTO.getPassenger()) {
                    if (Objects.equals(passenger.getMainDataId(), touristReq.getTouristTypeId())) {
                        if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.YES.getCode())) {
                            occupyBedNum = occupyBedNum + touristReq.getPeople();
                        } else if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.NO.getCode())) {
                            notOccupyBedNum = notOccupyBedNum + touristReq.getPeople();
                        }
                    }
                }
            }
            Integer rooms = 0;
            //计算最终所需房间数
            if (seriesTripScheduleDataDTO.getNightDays() > 0) {
                Map<String, Integer> roomsResult = SingleRoomUtil.computeRooms(occupyBedNum, notOccupyBedNum,
                        req.getRoomNum(),
                        (double) seriesTripScheduleTeamRuleDTO.getOccupyBedNum(),
                        (double) seriesTripScheduleTeamRuleDTO.getNotOccupyBedNum());
                rooms = roomsResult.get("rooms");
                Integer singleRoomNum = roomsResult.get("singleRoomNum");
                if (rooms > 0 && singleRoomNum > 0) {

                    //单房差
                    SeriesTripScheduleDefaultFeeAdjustDTO singleRoomAdjustDTO = null;
                    if (CollectionUtils.isNotEmpty(feeAdjustList)) {
                        for (SeriesTripScheduleDefaultFeeAdjustDTO seriesTripScheduleDefaultFeeAdjustDTO : feeAdjustList) {
                            if (Objects.equals(seriesTripScheduleDefaultFeeAdjustDTO.getMainDataId(), Constants.SINGLE_ROOM_ID)) {
                                singleRoomAdjustDTO = seriesTripScheduleDefaultFeeAdjustDTO;
                                break;
                            }
                        }
                    }
                    //TODO 含几晚
                    if (singleRoomAdjustDTO != null) {
                        SeriesOrderCalculationItemDTO collectionItem = new SeriesOrderCalculationItemDTO();
                        collectionItem.setProjectName(singleRoomAdjustDTO.getProjectName());
                        collectionItem.setAmount(Assist.setScale(singleRoomAdjustDTO.getCostAmount().multiply(new BigDecimal(singleRoomAdjustDTO.getExchangeRate()))));
                        collectionItem.setQuantity(singleRoomNum);
                        collectionItem.setTotalAmount(Assist.setScale(singleRoomAdjustDTO.getCostAmount().multiply(new BigDecimal(singleRoomNum)).multiply(new BigDecimal(singleRoomAdjustDTO.getExchangeRate()))));
                        singleRoomItemList.add(collectionItem);
                        totalAmount = totalAmount.add(collectionItem.getTotalAmount());
                    }
                }
            }
            if (CollectionUtils.isNotEmpty(costCollectionList)) {
                for (SeriesTripScheduleDefaultCostCollectionDTO seriesTripScheduleDefaultCostCollectionDTO : costCollectionList) {
                    for (SeriesOrderTouristReq touristReq : touristList) {
                        SeriesTripScheduleDefaultCostTouristTypeDTO selectTypeDTO = null;
                        //判断代收费用中是否有相同游客类型的代收费用
                        for (SeriesTripScheduleDefaultCostTouristTypeDTO typeDTO : seriesTripScheduleDefaultCostCollectionDTO.getCostCollectionTypeList()) {
                            if (Objects.equals(typeDTO.getTouristTypeId(), touristReq.getTouristTypeId())) {
                                selectTypeDTO = typeDTO;
                                break;
                            }
                        }
                        if (selectTypeDTO == null) {
                            continue;
                        }
                        SeriesOrderCalculationItemDTO collectionItem = new SeriesOrderCalculationItemDTO();
                        collectionItem.setProjectName(seriesTripScheduleDefaultCostCollectionDTO.getProjectName() + "（" + touristReq.getTouristTypeName() + "）");
                        collectionItem.setAmount(selectTypeDTO.getTotalAmount());
                        collectionItem.setQuantity(touristReq.getPeople());
                        collectionItem.setTotalAmount(selectTypeDTO.getTotalAmount().multiply(new BigDecimal(touristReq.getPeople())));
                        collectionItemDTOList.add(collectionItem);

                        totalAmount = totalAmount.add(collectionItem.getTotalAmount());
                    }
                }
            }

            dto.setTotalAmount(totalAmount);
            dto.setGroupFeeItemList(groupFeeItemDTOList);
            dto.setCollectionItemList(collectionItemDTOList);
            dto.setSingleRoomItemList(singleRoomItemList);
            dto.setRooms(rooms);
        } else if (Objects.equals(tripScheduleDTO.getCostSharingType(), CostSharingType.CUSTOM.getCode())) {
            //自定义
            TripCustomCostReq tripCustomCostReq = tripScheduleDTO.getTripCustomCostReq();
            List<TripCustomSalePriceReq> customSalePriceList = tripCustomCostReq.getCustomSalePriceList();

            List<SeriesTripDefaultCostCollectionReq> customCostCollectionList = tripCustomCostReq.getCostCollectionList();
            List<SeriesTripCustomFeeAdjustReq> customFeeAdjustList = tripCustomCostReq.getFeeAdjustList();
            //占床数
            int occupyBedNum = 0;
            //不占床数
            int notOccupyBedNum = 0;
            for (SeriesOrderTouristReq touristReq : touristList) {
                //团费
                TripCustomSalePriceReq selectTripCustomSalePriceReq = null;
                A:
                for (TripCustomSalePriceReq tripCustomSalePriceReq : customSalePriceList) {
                    if (Objects.equals(tripCustomSalePriceReq.getMainDataId(), touristReq.getTouristTypeId())) {
                        if (Objects.equals(tripCustomSalePriceReq.getDateType(), DataType.WEEK.getCode())) {
                            for (Integer checkWeekDay : tripCustomSalePriceReq.getCheckWeekDays()) {
                                if (Objects.equals(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue(), checkWeekDay)) {
                                    selectTripCustomSalePriceReq = tripCustomSalePriceReq;
                                    break A;
                                }
                            }
                        } else if (Objects.equals(tripCustomSalePriceReq.getDateType(), DataType.DATE.getCode())) {
                            if (tripScheduleDTO.getDepartureDate().compareTo(tripCustomSalePriceReq.getDateBegin()) >= 0
                                    && tripScheduleDTO.getDepartureDate().compareTo(tripCustomSalePriceReq.getDateEnd()) <= 0) {
                                selectTripCustomSalePriceReq = tripCustomSalePriceReq;
                                break A;
                            }
                        }
                    }
                }
                if (selectTripCustomSalePriceReq == null) {
                    throw new BusinessException(SystemError.SYS_411);
                }
                SeriesOrderCalculationItemDTO groupFeeItem = new SeriesOrderCalculationItemDTO();
                groupFeeItem.setTouristTypeId(touristReq.getTouristTypeId());
                groupFeeItem.setProjectName(touristReq.getTouristTypeName());
                BigDecimal price = iSeriesTripScheduleService.calcSalePriceInfoHandle(1, tripScheduleDTO.getId(), req.getUserId(), selectTripCustomSalePriceReq.getGroupCustomerPrice());
                groupFeeItem.setAmount(price);
                groupFeeItem.setQuantity(touristReq.getPeople());
                groupFeeItem.setTotalAmount(selectTripCustomSalePriceReq.getGroupCustomerPrice().multiply(new BigDecimal(touristReq.getPeople())));
                groupFeeItemDTOList.add(groupFeeItem);

                totalAmount = totalAmount.add(groupFeeItem.getTotalAmount());

                //单房差
                for (Passenger passenger : seriesTripScheduleTeamRuleDTO.getPassenger()) {
                    if (Objects.equals(passenger.getMainDataId(), touristReq.getTouristTypeId())) {
                        if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.YES.getCode())) {
                            occupyBedNum = occupyBedNum + touristReq.getPeople();
                        } else if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.NO.getCode())) {
                            notOccupyBedNum = notOccupyBedNum + touristReq.getPeople();
                        }
                    }
                }
            }
            Integer rooms = 0;
            //计算最终所需房间数
            if (seriesTripScheduleDataDTO.getNightDays() > 0) {
                //计算最终所需房间数
                Map<String, Integer> roomsResult = SingleRoomUtil.computeRooms(occupyBedNum, notOccupyBedNum,
                        req.getRoomNum(),
                        (double) seriesTripScheduleTeamRuleDTO.getOccupyBedNum(),
                        (double) seriesTripScheduleTeamRuleDTO.getNotOccupyBedNum());
                rooms = roomsResult.get("rooms");
                Integer singleRoomNum = roomsResult.get("singleRoomNum");
                if (rooms > 0 && singleRoomNum > 0) {
                    for (SeriesOrderTouristReq touristReq : touristList) {
                        //单房差
                        SeriesTripCustomFeeAdjustReq singleRoomCustomFeeAdjustReq = null;
                        CustomCostReq singleRoomCustomCostReq = null;
                        B:
                        for (SeriesTripCustomFeeAdjustReq seriesTripCustomFeeAdjustReq : customFeeAdjustList) {
                            if (Objects.equals(seriesTripCustomFeeAdjustReq.getMainDataId(), Constants.SINGLE_ROOM_ID)) {
                                for (CustomCostReq customCostReq : seriesTripCustomFeeAdjustReq.getCustomCostList()) {
                                    if (Objects.equals(customCostReq.getMainDataId(), touristReq.getTouristTypeId())) {
                                        if (Objects.equals(customCostReq.getDateType(), DataType.WEEK.getCode())) {
                                            for (Integer checkWeekDay : customCostReq.getCheckWeekDays()) {
                                                if (Objects.equals(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue(), checkWeekDay)) {
                                                    singleRoomCustomFeeAdjustReq = seriesTripCustomFeeAdjustReq;
                                                    singleRoomCustomCostReq = customCostReq;
                                                    break B;
                                                }
                                            }
                                        } else if (Objects.equals(customCostReq.getDateType(), DataType.DATE.getCode())) {
                                            if (tripScheduleDTO.getDepartureDate().compareTo(customCostReq.getDateBegin()) >= 0
                                                    && tripScheduleDTO.getDepartureDate().compareTo(customCostReq.getDateEnd()) <= 0) {
                                                singleRoomCustomFeeAdjustReq = seriesTripCustomFeeAdjustReq;
                                                singleRoomCustomCostReq = customCostReq;
                                                break B;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        //调整费用 行程晚大于0
                        if (singleRoomCustomCostReq != null) {
                            SeriesOrderCalculationItemDTO collectionItem = new SeriesOrderCalculationItemDTO();
                            collectionItem.setTouristTypeId(touristReq.getTouristTypeId());
                            collectionItem.setProjectName(singleRoomCustomFeeAdjustReq.getProjectName() + "（" + touristReq.getTouristTypeName() + "）");
                            collectionItem.setAmount(Assist.setScale(singleRoomCustomCostReq.getPrice().multiply(new BigDecimal(singleRoomCustomFeeAdjustReq.getExchangeRate()))));
                            collectionItem.setQuantity(0);
                            collectionItem.setTotalAmount(new BigDecimal(0));
                            singleRoomItemList.add(collectionItem);
                            for (int i = 0; i < touristReq.getPeople(); i++) {
                                if (singleRoomNum > 0) {
                                    //累计调整费用
                                    if (Objects.equals(singleRoomCustomFeeAdjustReq.getAdjustType(), PlusTypeCode.PLUS.getCode())) {
                                        collectionItem.setQuantity(collectionItem.getQuantity() + 1);
                                        collectionItem.setTotalAmount(collectionItem.getTotalAmount().add(singleRoomCustomCostReq.getPrice()));
                                        BigDecimal exchangeRateTotalAmount = Assist.setScale(collectionItem.getTotalAmount().multiply(new BigDecimal(singleRoomCustomFeeAdjustReq.getExchangeRate())));
                                        collectionItem.setTotalAmount(exchangeRateTotalAmount);
                                        totalAmount = totalAmount.add(collectionItem.getTotalAmount());
                                    } else if (Objects.equals(singleRoomCustomFeeAdjustReq.getAdjustType(), PlusTypeCode.SUBTRACT.getCode())) {
                                        collectionItem.setQuantity(collectionItem.getQuantity() - 1);
                                        collectionItem.setTotalAmount(collectionItem.getTotalAmount().subtract(singleRoomCustomCostReq.getPrice()));
                                        BigDecimal exchangeRateTotalAmount = Assist.setScale(collectionItem.getTotalAmount().multiply(new BigDecimal(singleRoomCustomFeeAdjustReq.getExchangeRate())));
                                        collectionItem.setTotalAmount(exchangeRateTotalAmount);
                                        totalAmount = totalAmount.subtract(collectionItem.getTotalAmount());
                                    }

                                    singleRoomNum--;
                                }
                            }
                        }
                    }
                }
            }
            for (SeriesTripDefaultCostCollectionReq seriesTripScheduleDefaultCostCollectionDTO : customCostCollectionList) {
                for (SeriesOrderTouristReq touristReq : touristList) {
                    SeriesTripDefaultCostCollectionTypeReq selectTypeDTO = null;
                    //判断代收费用中是否有相同游客类型的代收费用
                    for (SeriesTripDefaultCostCollectionTypeReq typeDTO : seriesTripScheduleDefaultCostCollectionDTO.getCostCollectionTypeList()) {
                        if (Objects.equals(typeDTO.getTouristTypeId(), touristReq.getTouristTypeId())) {
                            selectTypeDTO = typeDTO;
                            break;
                        }
                    }
                    if (selectTypeDTO == null) {
                        continue;
                    }
                    SeriesOrderCalculationItemDTO collectionItem = new SeriesOrderCalculationItemDTO();
                    collectionItem.setProjectName(seriesTripScheduleDefaultCostCollectionDTO.getProjectName() + "（" + touristReq.getTouristTypeName() + "）");
                    collectionItem.setAmount(selectTypeDTO.getTotalAmount());
                    collectionItem.setQuantity(touristReq.getPeople());
                    collectionItem.setTotalAmount(selectTypeDTO.getTotalAmount().multiply(new BigDecimal(touristReq.getPeople())));
                    collectionItemDTOList.add(collectionItem);

                    totalAmount = totalAmount.add(collectionItem.getTotalAmount());
                }
            }

            dto.setTotalAmount(totalAmount);
            dto.setGroupFeeItemList(groupFeeItemDTOList);
            dto.setCollectionItemList(collectionItemDTOList);
            dto.setSingleRoomItemList(singleRoomItemList);
            dto.setRooms(rooms);
        }
        return Result.success(dto);
    }


    /**
     * 计算单房差-C端
     */
    @Override
    public Result<SeriesOrderCalculationToCDTO> calculationToC(SeriesOrderCalculationReq req) {
        SeriesOrderCalculationToCDTO dto = new SeriesOrderCalculationToCDTO();
        // 团费
        List<SeriesOrderCalculationItemDTO> groupFeeItemDTOList = new ArrayList<>();
        // 单房差
        List<SeriesOrderCalculationItemDTO> singleRoomItemList = new ArrayList<>();
        // 其它代收费用
        List<SeriesOrderCalculationItemToCDTO> collectionItemDTOList = new ArrayList<>();

        // 前端传入旅客类型
        List<SeriesOrderTouristReq> orderTouristReqs = req.getTouristList();
        Set<SeriesOrderTouristReq> touristList = orderTouristReqs.stream().filter(item -> item.getPeople() > 0).collect(Collectors.toSet());
        // 缓存的旅客类型信息
        ScheduleInfoCacheDTO scheduleInfoCache = getScheduleInfoCache(req.getChannelId(), req.getScheduleId());
        if (ObjectUtils.isEmpty(scheduleInfoCache)) {
            return Result.failed(SystemError.TOUR_ORDER_30028);
        }
        List<TripTouristTypeDTO> touristTypes = scheduleInfoCache.getTouristTypes();

        // 最终占床数
        Integer rooms = 0;
        // 最终需补单房差人数
        Integer singleRoomNum = 0;
        BigDecimal totalAmount = new BigDecimal(0);
        if (scheduleInfoCache.getNightDays() > 0) {
            //占床数
            int occupyBedNum = 0;
            //不占床数
            int notOccupyBedNum = 0;
            // 计算占床数&不占床数
            for (TripTouristTypeDTO touristType : touristTypes) {
                for (SeriesOrderTouristReq orderTouristReq : orderTouristReqs) {
                    if (Objects.equals(touristType.getId(), orderTouristReq.getTouristTypeId())) {
                        if (Objects.equals(touristType.getIsOccupyBed(), IsOccupyBedCode.YES.getCode())) {
                            occupyBedNum = occupyBedNum + orderTouristReq.getPeople();
                        } else if (Objects.equals(touristType.getIsOccupyBed(), IsOccupyBedCode.NO.getCode())) {
                            notOccupyBedNum = notOccupyBedNum + orderTouristReq.getPeople();
                        }
                    }
                }
            }

            if (req.getRoomNum() > 0) {
                // 计算最终所需房间数
                Map<String, Integer> roomsResult = SingleRoomUtil.computeRooms(occupyBedNum, notOccupyBedNum,
                        req.getRoomNum(),
                        (double) scheduleInfoCache.getOccupyBedNum(),
                        (double) scheduleInfoCache.getNotOccupyBedNum());
                // 最终占床数
                rooms = roomsResult.get("rooms");
                // 最终需补单房差人数
                singleRoomNum = roomsResult.get("singleRoomNum");
            }
        }

        // 费用计算
        for (TripTouristTypeDTO touristType : touristTypes) {
            for (SeriesOrderTouristReq touristReq : touristList) {
                if (touristType.getId().longValue() == touristReq.getTouristTypeId().longValue()) {
                    // 单房差
                    if (rooms > 0 && singleRoomNum > 0) {
                        List<TripCostCollectionDTO> adjustFeeList = touristType.getAdjustFeeList();
                        if (CollectionUtil.isNotEmpty(adjustFeeList)) {
                            for (TripCostCollectionDTO adjust : adjustFeeList) {
                                if (adjust.getId().equals(Constants.SINGLE_ROOM_ID)) {
                                    SeriesOrderCalculationItemDTO collectionItem = new SeriesOrderCalculationItemDTO();
                                    collectionItem.setProjectName(adjust.getName());
                                    collectionItem.setAmount(adjust.getPrice());
                                    collectionItem.setQuantity(singleRoomNum);
                                    collectionItem.setTotalAmount(adjust.getPrice().multiply(new BigDecimal(singleRoomNum)));
                                    singleRoomItemList.add(collectionItem);
                                    totalAmount = totalAmount.add(collectionItem.getTotalAmount());
                                    singleRoomNum--;
                                    break;
                                }
                            }
                        }
                    }

                    // 团费
                    SeriesOrderCalculationItemDTO groupFeeItem = new SeriesOrderCalculationItemDTO();
                    groupFeeItem.setProjectName("团费（" + touristType.getName() + "）");
                    groupFeeItem.setTouristType(touristType.getName());
                    groupFeeItem.setTouristTypeId(touristType.getId());
                    groupFeeItem.setAmount(scheduleInfoCache.getPrice());
                    groupFeeItem.setQuantity(touristReq.getPeople());
                    groupFeeItem.setTotalAmount(scheduleInfoCache.getPrice().multiply(new BigDecimal(touristReq.getPeople())));
                    groupFeeItemDTOList.add(groupFeeItem);
                    totalAmount = totalAmount.add(groupFeeItem.getTotalAmount());

                    // 代收费用
                    if (touristReq.getTouristTypeId().equals(touristType.getId())) {
                        List<TripCostCollectionDTO> costList = touristType.getCostList();
                        for (TripCostCollectionDTO tripCostCollectionDTO : costList) {
                            SeriesOrderCalculationItemToCDTO collectionItemDTO = new SeriesOrderCalculationItemToCDTO();
                            collectionItemDTO.setProjectName(tripCostCollectionDTO.getName());
                            collectionItemDTO.setAmount(tripCostCollectionDTO.getPrice().toString());
                            collectionItemDTO.setQuantity(touristReq.getPeople());
                            collectionItemDTO.setTotalAmount(tripCostCollectionDTO.getPrice().multiply(new BigDecimal(touristReq.getPeople())));
                            collectionItemDTOList.add(collectionItemDTO);
                            totalAmount = totalAmount.add(collectionItemDTO.getTotalAmount());
                        }
                    }
                }
            }
        }

        dto.setTotalAmount(totalAmount);
        groupFeeItemDTOList.addAll(singleRoomItemList);
        dto.setGroupFeeItemList(groupFeeItemDTOList);
        dto.setCollectionItemList(collectionItemDTOList);
        dto.setRooms(rooms);
        return Result.success(dto);
    }

    /**
     * 计算调整费用&代收费用
     *
     * @param adjustType   加减类型
     * @param adjustAmount 加减金额
     * @param basePrice    基础金额
     * @return
     */
    private BigDecimal feeIncrease(Integer adjustType, BigDecimal adjustAmount, BigDecimal basePrice) {
        if (ObjectUtils.isNotEmpty(adjustAmount) && ObjectUtils.isNotEmpty(adjustType)) {
            if (adjustType.intValue() == PlusTypeCode.PLUS.getCode().intValue()) {
                return adjustAmount.add(basePrice).setScale(0, BigDecimal.ROUND_UP);
            }
            if (adjustType.intValue() == PlusTypeCode.SUBTRACT.getCode().intValue()) {
                return adjustAmount.subtract(basePrice).setScale(0, BigDecimal.ROUND_UP);
            }
        }
        return basePrice.setScale(0, BigDecimal.ROUND_UP);
    }

    /**
     * 查询团期团费
     *
     * @param channelId
     * @param scheduleId
     * @return
     */
    private ScheduleInfoCacheDTO getScheduleInfoCache(Long channelId, Long scheduleId) {
        // 通过团期id从es获取行程id
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.nestedQuery("schedules", QueryBuilders.termQuery("schedules.id", scheduleId), ScoreMode.None));
        searchSourceBuilder.query(boolQuery);
        searchSourceBuilder.fetchSource("id", "");
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRIP_INDEX).source(searchSourceBuilder);
        String id = "";
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            SearchHit[] hits = response.getHits().getHits();
            if (ObjectUtils.isNotEmpty(hits)) {
                String str = hits[0].getSourceAsString();
                TripCacheDTO tripCacheDTO = JSON.parseObject(str, TripCacheDTO.class);
                id = tripCacheDTO.getId().toString();
                if (StringUtils.isEmpty(id)) {
                    Result.failed(SystemError.TOUR_ORDER_30028);
                }
            }
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }

        // 通过行程id从redis获取团期缓存
        if (StringUtils.isNotEmpty(id)) {
            BoundHashOperations<String, String, String> hashOps = redis.boundHashOps(RedisConstants.TOUR_SCHEDULE_DETAILS + channelId + ":");
            if (!hashOps.hasKey(id)) {
                TripCacheUpdateReq tripCacheUpdateReq = new TripCacheUpdateReq().setIds(Arrays.asList(Long.valueOf(id)));
                seriesTripAppService.updateTripCache(tripCacheUpdateReq);
            }

            String str = hashOps.get(id);
            TripDetailsCacheDTO tripDetailsCacheDTO = JSON.parseObject(str, TripDetailsCacheDTO.class);
            List<ScheduleInfoCacheDTO> dateListDTOS = tripDetailsCacheDTO.getDateListDTOS();
            for (ScheduleInfoCacheDTO dateListDTO : dateListDTOS) {
                if (dateListDTO.getId().longValue() == scheduleId.longValue()) {
                    return dateListDTO;
                }
            }
        }
        return null;
    }

    /**
     * 关闭占位
     */
    @Override
    public Result closeOccupy(Long orderId) {
        SeriesOrder dbOrder = getById(orderId);
        if (dbOrder == null) {
            return Result.failed(SystemError.SYS_411);
        }
        if (!Objects.equals(dbOrder.getIsDeleted(), IsDeletedCode.NO.getCode())) {
            return Result.failed(SystemError.SYS_423);
        }
        if (!Objects.equals(PlaceOrderStatusCode.WAIT_CONFIRM.getCode(), dbOrder.getPlaceOrderStatus())) {
            return Result.failed(SeriesOrderErrorCode.CLOSE_OCCUPY_PLACE_ORDER_STATUS_LIMIT);
        }
        dbOrder.setIsDeleted(IsDeletedCode.YES.getCode());
        updateById(dbOrder);

        UpdateScheduleNumReq updateScheduleNumReq = new UpdateScheduleNumReq();
        updateScheduleNumReq.setId(dbOrder.getScheduleId());
        updateScheduleNumReq.setNum(dbOrder.getTotalPeople());
        Result result = iSeriesTripScheduleService.updateScheduleNum(updateScheduleNumReq);
        if (!result.isSuccess()) {
            throw new BusinessException(SystemError.SYS_500);
        }
        return Result.success();
    }

    /**
     * 关闭留位
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result closeKeep(Long orderId) {
        SeriesOrder dbOrder = getById(orderId);
        if (dbOrder == null) {
            return Result.failed(SystemError.SYS_411);
        }
        if (!Objects.equals(dbOrder.getIsDeleted(), IsDeletedCode.NO.getCode())) {
            return Result.failed(SystemError.SYS_423);
        }
        QueryWrapper<SeriesOrderAmountStatistics> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SeriesOrderAmountStatistics::getOrderId, dbOrder.getId());
        SeriesOrderAmountStatistics dbStatistics = seriesOrderAmountStatisticsMapper.selectOne(queryWrapper);
        if (dbStatistics == null) {
            return Result.failed(SystemError.SYS_411);
        }
        //只有实收=0才，取消订单
        if (dbStatistics.getTotalPaidIn().compareTo(new BigDecimal(0)) == 0) {
            dbOrder.setIsDeleted(IsDeletedCode.YES.getCode());
            updateById(dbOrder);

            UpdateScheduleNumReq updateScheduleNumReq = new UpdateScheduleNumReq();
            updateScheduleNumReq.setId(dbOrder.getScheduleId());
            updateScheduleNumReq.setNum(dbOrder.getTotalPeople());
            Result result = iSeriesTripScheduleService.updateScheduleNum(updateScheduleNumReq);
            if (!result.isSuccess()) {
                throw new BusinessException(SystemError.SYS_500);
            }
        }
        return Result.success();
    }

    /**
     * 绑定会员
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result bindMember(SeriesOrderBindMemberReq req) {
        CrmMemberQueryReq crmMemberQueryReq = EntityUtil.copy(req, CrmMemberQueryReq.class);
        CrmAccountDTO crmAccountDTO = iCrmMemberService.queryAccountDetail(crmMemberQueryReq);
        if (crmAccountDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        //更新会员信息
        SeriesOrder dbOrder = seriesOrderMapper.selectById(req.getOrderId());
        if (Objects.equals(dbOrder.getOrderType(), OrderTypeCode.PROXY.getCode())) {
            return Result.failed(SeriesOrderErrorCode.BIND_MEMBER_PROXY_LIMIT);
        }
        dbOrder.setMemberId(crmAccountDTO.getConIntegrationId());
        dbOrder.setMemberEmail(crmAccountDTO.getConEmailAddr());
        dbOrder.setMemberMobile(crmAccountDTO.getConCellPhNum());
        dbOrder.setMemberLevel(String.valueOf(crmAccountDTO.getLevel()));
        dbOrder.setMemberName(crmAccountDTO.getNameCn());
        dbOrder.setMemberType(crmAccountDTO.getType());

        if (Objects.equals(crmAccountDTO.getType(), CrmAccountType.STAR.getCode())) {
            ContactQueryDTO contactQueryDTO = iCrmMemberService.queryMember(crmMemberQueryReq);
            if (contactQueryDTO == null) {
                throw new BusinessException(SystemError.SYS_411);
            }
            dbOrder.setMemberScore(String.valueOf(contactQueryDTO.getMember().getPoint1Value()));
        }
        updateById(dbOrder);
        return Result.success();
    }

    /**
     * 查询所属系列团团期ID列表
     *
     * @param req
     * @return
     */
    @Override
    public List<Long> queryMyGroupId(SeriesOrderMyGroupIdQueryReq req) {
        List<Long> idList = seriesOrderMapper.queryMyGroupId(req);
        return idList;
    }

    /**
     * 获取订单号
     */
    public String getOrderNumber(Long userId) {
        //T+部門代碼+員工編號+年後2位+月日4位+3位隨機數字
        SysDepartmentDTO departmentDTO = iSysDepartmentService.queryByUserId(userId);
        if (departmentDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        UserDTO userDTO = iSysUserService.loadUserInfo(userId, 1);
        if (userDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        LocalDateTime now = LocalDateTime.now();
        return "T" + departmentDTO.getDeptCode() + userDTO.getEmployeeNumber() +
                now.format(DateTimeFormatter.ofPattern(Utils.yyMMdd)) + Utils.getRandom3();
    }

    /**
     * 获取退团单号
     */
    @Deprecated
    public String getQuitNumber() {
        LocalDateTime now = LocalDateTime.now();
        return "TTD" + now.format(DateTimeFormatter.ofPattern(Utils.yyMMdd)) + Utils.getRandom2();
    }

    /**
     * 获取发票订单号
     */
    public String getInvoiceNumber(Long userId) {
        //門市編號+員工編號+月日4位+時分秒6位
        SysDepartmentDTO departmentDTO = iSysDepartmentService.queryByUserId(userId);
        if (departmentDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        UserDTO userDTO = iSysUserService.loadUserInfo(userId, 1);
        if (userDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        LocalDateTime now = LocalDateTime.now();
        return departmentDTO.getDeptCode() + userDTO.getEmployeeNumber() +
                now.format(DateTimeFormatter.ofPattern(Utils.yyMMdd)) + now.format(DateTimeFormatter.ofPattern(Utils.HHmmss));
    }

    /**
     * 获取收据订单号（销售）
     */
    public String getReceiptNumberSale(Long userId) {
        //門市編號+員工編號+年後2位+月日4位+A+時分秒6位+（S）
        SysDepartmentDTO departmentDTO = iSysDepartmentService.queryByUserId(userId);
        if (departmentDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        UserDTO userDTO = iSysUserService.loadUserInfo(userId, 1);
        if (userDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        LocalDateTime now = LocalDateTime.now();
        return departmentDTO.getDeptCode() + userDTO.getEmployeeNumber() +
                now.format(DateTimeFormatter.ofPattern(Utils.yyMMdd)) + "A" + now.format(DateTimeFormatter.ofPattern(Utils.HHmmss)) + Utils.getRandom6() + "（S）";
    }

    /**
     * 获取收据订单号（保险）
     */
    public String getReceiptNumberInsurance(Long userId) {
        //門市編號+員工編號+年後2位+月日4位+B+時分秒6位+（S）
        SysDepartmentDTO departmentDTO = iSysDepartmentService.queryByUserId(userId);
        if (departmentDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        UserDTO userDTO = iSysUserService.loadUserInfo(userId, 1);
        if (userDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        LocalDateTime now = LocalDateTime.now();
        return departmentDTO.getDeptCode() + userDTO.getEmployeeNumber() +
                now.format(DateTimeFormatter.ofPattern(Utils.yyMMdd)) + "B" + now.format(DateTimeFormatter.ofPattern(Utils.HHmmss)) + Utils.getRandom6() + "（S）";
    }

    /**
     * 获取收据单号（通知书）
     */
    public String getReceiptNumberQuit(Long userId) {
        //門市編號+員工編號+年後2位+月日4位+A+時分秒6位+（T）
        SysDepartmentDTO departmentDTO = iSysDepartmentService.queryByUserId(userId);
        if (departmentDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        UserDTO userDTO = iSysUserService.loadUserInfo(userId, 1);
        if (userDTO == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        LocalDateTime now = LocalDateTime.now();
        return departmentDTO.getDeptCode() + userDTO.getEmployeeNumber() +
                now.format(DateTimeFormatter.ofPattern(Utils.yyMMdd)) + "A" + now.format(DateTimeFormatter.ofPattern(Utils.HHmmss)) + Utils.getRandom6() + "（T）";
    }

    /**
     * 获取收款单号
     */
    public String getCollectionNumber() {
        //SKD+年後2位+月日4位+時分秒6位+2位隨機數字
        LocalDateTime now = LocalDateTime.now();
        return "SKD" + now.format(DateTimeFormatter.ofPattern(Utils.yyMMddHHmmss)) + Utils.getRandom2();
    }

    /**
     * 获取退款单号
     */
    public String getRefundNumber() {
        //TKD+年後2位+月日4位+時分秒6位+2位隨機數字
        LocalDateTime now = LocalDateTime.now();
        return "TKD" + now.format(DateTimeFormatter.ofPattern(Utils.yyMMddHHmmss)) + Utils.getRandom2();//如果不足两位，前面补0;
    }

    /**
     * 获取销售人并
     */
    private UserDTO getSaleMan() {
        DispatchOrderRuleGetUserReq dispatchOrderRuleGetUserReq = new DispatchOrderRuleGetUserReq();
        dispatchOrderRuleGetUserReq.setBusinessTypeId(SystemBusinessType.OUTBOUND_TRAVEL.getCode());
        dispatchOrderRuleGetUserReq.setCompanyType(CompanyType.HK_CT.getCode());
        Result<Long> result = dispatchOrderRuleService.getDispatchUserId(dispatchOrderRuleGetUserReq);
        if (!result.isSuccess()) {
            log.error("【旅行团APP-提交订单】获取销售人失败:{},msg:{}", result.getCode(), result.getMsg());
            throw new BusinessException(SystemError.getDefined(result.getCode()));
        }
        UserDTO saleUser = iSysUserService.queryCacheUser(result.getData());
        return saleUser;
    }

    /**
     * 旅游团-下单（C端）
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result add(ClientSeriesOrderAddReq req, AppReq appReq) {
        // 可销售余位验证
        Integer remain = iSeriesTripScheduleService.queryScheduleRemain(req.getScheduleId());
        List<ClientTouristInfoReq> clientTouristInfoReqs = req.getTouristList();
        List<ClientTouristInfoReq> touristList = clientTouristInfoReqs.stream()
                .filter(item -> ObjectUtils.isNotEmpty(item.getMainDataId())).collect(Collectors.toList());
        if (ObjectUtils.isEmpty(remain) || remain < touristList.size()) {
            return Result.failed(SystemError.TOUR_ORDER_30029);
        }

        // 会员积分验证
        Long score = null;
        AppUserDTO userDTO = null;
        if (ObjectUtils.isNotEmpty(req.getScore())) {
            if (ObjectUtils.isEmpty(req.getUserId())) {
                return Result.failed(SystemError.USER_1000);
            }
            if (!req.getMemberType().equals(MemberType.STAR_CLUB_MEMBER.getCode())) {
                return Result.failed(SystemError.STAR_VIP_20008);
            }
            userDTO = iUserService.queryCacheUser(req.getUserId());
            if (ObjectUtils.isEmpty(userDTO)) {
                return Result.failed(SystemError.TOUR_ORDER_30030);
            }
            Result<Contact> contactResult = starVipUserService.userInfoQuery(new UserInfoQueryReq().setId(userDTO.getMemberId()));
            LoyMember loyMember = contactResult.getData().getListOfLoyMember().getLoyMember().get(0);
            score = Long.parseLong(loyMember.getPoint1Value());
            if (score < req.getScore()) {
                return Result.failed(SystemError.TOUR_ORDER_30031);
            }
        }

        // 行程Id
        Long tripId = iSeriesTripScheduleService.findScheduleTripIdById(req.getScheduleId());
        // 旅客总数量
        Integer totalPeopleNumber = touristList.size();

        SeriesOrder order = EntityUtil.copy(req, SeriesOrder.class);
        order.setInternalRemark(req.getMark());
        order.setId(SnowflakeIdWorker.nextId());
        LocalDateTime now = LocalDateTime.now();

        //获取团期
        SeriesTripScheduleDTO tripScheduleDTO = iSeriesTripScheduleService.getTripScheduleId(req.getScheduleId());
        if (tripScheduleDTO == null) {
            throw new BusinessException(SystemError.TOUR_30012);
        }

        // 获取业务类型
        Integer businessType = seriesTripService.findTripBusinessTypeById(tripId);
        // 销售员信息
        getSaleMan(order, appReq.getCompanyType(), now, businessType);

        SeriesTripScheduleDataDTO seriesTripScheduleDataDTO = tripScheduleDTO.getSeriesTripScheduleDataDTO();
        SeriesTripScheduleTeamRuleDTO seriesTripScheduleTeamRuleDTO = tripScheduleDTO.getSeriesTripScheduleTeamRuleDTO();

        //占床数
        int occupyBedNum = 0;
        //不占床数
        int notOccupyBedNum = 0;

        int nightDays = ObjectUtils.isEmpty(seriesTripScheduleDataDTO.getNightDays()) ? 0 : seriesTripScheduleDataDTO.getNightDays();

        List<SeriesOrderTouristInfoSaveBatchReq> touristInfoSaveBatchReqList = new ArrayList<>();
        List<SeriesOrderTouristOtherFeeSaveBatchReq> otherFeeSaveBatchReqList = new ArrayList<>();
        List<SeriesOrderTouristFeeAdjustSaveBatchReq> adjustSaveBatchReqList = new ArrayList<>();

        //团费
        BigDecimal orderGroupFee = new BigDecimal(0);
        //应收
        BigDecimal orderTotalReceivables = new BigDecimal(0);
        //实收
        BigDecimal orderTotalPaidIn = new BigDecimal(0);
        //已退款
        BigDecimal orderRefundAmount = new BigDecimal(0);
        //代收费用
        BigDecimal orderCollectionFee = new BigDecimal(0);
        //调整费用
        BigDecimal orderAdjustmentCost = new BigDecimal(0);
        //其他金额
        BigDecimal orderOtherAmount = new BigDecimal(0);
        //已出单据金额
        BigDecimal orderReceiptedAmount = new BigDecimal(0);
        //未收
        BigDecimal orderRemainingReceivables = new BigDecimal(0);

        for (ClientTouristInfoReq touristReq : touristList) {
            //判断年龄
            List<Passenger> passengers = tripScheduleDTO.getSeriesTripScheduleTeamRuleDTO().getPassenger();
            for (Passenger passenger : passengers) {
                if (Objects.equals(passenger.getMainDataId(), touristReq.getMainDataId())) {
                    touristReq.setTouristTypeName(passenger.getName());
                    int age = touristReq.getBirthday().until(LocalDate.now()).getYears();
                    if (age < passenger.getAgeBegin() || age > passenger.getAgeEnd()) {
                        throw new BusinessException(SystemError.CUSTOM_ORDER_4004);
                    }
                }
            }

            if (nightDays > 0) {
                //单房差
                for (Passenger passenger : seriesTripScheduleTeamRuleDTO.getPassenger()) {
                    if (Objects.equals(passenger.getMainDataId(), touristReq.getMainDataId())) {
                        if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.YES.getCode())) {
                            occupyBedNum++;
                        } else if (Objects.equals(passenger.getIsOccupyBed(), IsOccupyBedCode.NO.getCode())) {
                            notOccupyBedNum++;
                        }
                    }
                }
            }
        }

        // 最终所需补单房差人数
        Integer singleRoomNum = 0;
        if (nightDays > 0) {
            // 计算最终所需补单房差人数
            Map<String, Integer> roomsResult = SingleRoomUtil.computeRooms(occupyBedNum, notOccupyBedNum,
                    req.getRoomNum(),
                    (double) seriesTripScheduleTeamRuleDTO.getOccupyBedNum(),
                    (double) seriesTripScheduleTeamRuleDTO.getNotOccupyBedNum());
            // Integer rooms = roomsResult.get("rooms");
            singleRoomNum = roomsResult.get("singleRoomNum");
        }

        order.setTripId(tripScheduleDTO.getSeriesTripScheduleDataDTO().getTripId());
        order.setTripTitle(tripScheduleDTO.getSeriesTripScheduleDataDTO().getTitle());
        order.setScheduleNumber(tripScheduleDTO.getTripNumber());
        order.setDepartDate(tripScheduleDTO.getDepartureDate());
        order.setTotalPeople(totalPeopleNumber);

        // 团期渠道加辐
        List<OfficialReq> officialList = tripScheduleDTO.getOfficialList();
        // 加减类型
        Integer adjustType = null;
        // 加减金额
        BigDecimal amount = null;
        if (CollectionUtil.isNotEmpty(officialList)) {
            for (OfficialReq officialReq : officialList) {
                if (officialReq.getScheduleId().longValue() == req.getScheduleId().longValue()
                        && officialReq.getChannelType().longValue() == req.getChannelId().longValue()) {
                    adjustType = officialReq.getAdjustType();
                    amount = officialReq.getAmount();
                    break;
                }
            }
        }

        // 订单统计
        if (Objects.equals(tripScheduleDTO.getCostSharingType(), CostSharingType.DEFAULT.getCode())) {
            // 默认模板
            TripScheduleDefaultCostDTO tripScheduleDefaultCostDTO = tripScheduleDTO.getTripScheduleDefaultCost();
            SeriesTripScheduleSellingPriceDTO seriesTripScheduleSellingPriceDTO = tripScheduleDefaultCostDTO.getSeriesTripScheduleSellingPriceDTO();
            List<SeriesTripScheduleDefaultCostCollectionDTO> costCollectionList = tripScheduleDefaultCostDTO.getCostCollectionList();
            List<SeriesTripScheduleDefaultFeeAdjustDTO> feeAdjustList = tripScheduleDefaultCostDTO.getFeeAdjustList();

            // 单房差
            SeriesTripScheduleDefaultFeeAdjustDTO singleRoomAdjustDTO = null;
            if (singleRoomNum > 0) {
                if (CollectionUtil.isNotEmpty(feeAdjustList)) {
                    for (SeriesTripScheduleDefaultFeeAdjustDTO seriesTripScheduleDefaultFeeAdjustDTO : feeAdjustList) {
                        if (Objects.equals(seriesTripScheduleDefaultFeeAdjustDTO.getMainDataId(), Constants.SINGLE_ROOM_ID)) {
                            singleRoomAdjustDTO = seriesTripScheduleDefaultFeeAdjustDTO;
                            break;
                        }
                    }
                }
            }

            for (ClientTouristInfoReq touristReq : touristList) {
                long touristId = touristReq.getMainDataId();
                //团费
                BigDecimal groupCustomerPrice = seriesTripScheduleSellingPriceDTO.getGroupCustomerPrice();
                BigDecimal groupFee = feeIncrease(adjustType, amount, groupCustomerPrice);
                //应收
                BigDecimal totalReceivables = new BigDecimal(0);
                //实收
                BigDecimal totalPaidIn = new BigDecimal(0);
                //已退款
                BigDecimal refundAmount = new BigDecimal(0);
                //代收费用
                BigDecimal collectionFee = new BigDecimal(0);
                //调整费用
                BigDecimal adjustmentCost = new BigDecimal(0);
                //其他金额
                BigDecimal otherAmount = new BigDecimal(0);
                //已出单据金额
                BigDecimal receiptedAmount = new BigDecimal(0);
                //未收
                BigDecimal remainingReceivables = new BigDecimal(0);
                // 代收费用项
                List<TouristCollectionFeeJson> collectionFeeJsonList = new ArrayList<>();

                if (CollectionUtil.isNotEmpty(costCollectionList)) {
                    for (SeriesTripScheduleDefaultCostCollectionDTO seriesTripScheduleDefaultCostCollectionDTO : costCollectionList) {
                        //判断代收费用中是否有相同游客类型的代收费用
                        for (SeriesTripScheduleDefaultCostTouristTypeDTO typeDTO : seriesTripScheduleDefaultCostCollectionDTO.getCostCollectionTypeList()) {
                            if (Objects.equals(typeDTO.getTouristTypeId(), touristReq.getMainDataId())) {
                                // 代收费用项
                                TouristCollectionFeeJson collectionFeeJson = new TouristCollectionFeeJson();
                                collectionFeeJson.setProjectName(seriesTripScheduleDefaultCostCollectionDTO.getProjectName());
                                collectionFeeJson.setMainDataId(seriesTripScheduleDefaultCostCollectionDTO.getMainDataId());
                                collectionFeeJson.setAdjustType(PlusTypeCode.PLUS.getCode());
                                collectionFeeJson.setTotalAmount(typeDTO.getTotalAmount().multiply(new BigDecimal(seriesTripScheduleDefaultCostCollectionDTO.getExchangeRate())).setScale(0, BigDecimal.ROUND_UP));
                                collectionFeeJsonList.add(collectionFeeJson);
                                //累计代收费用
                                collectionFee = collectionFee.add(collectionFeeJson.getTotalAmount());
                            }
                        }
                    }
                }

                //其他费用
                //调整费用
                if (singleRoomNum > 0 && singleRoomAdjustDTO != null) {
                    SeriesOrderTouristFeeAdjustSaveBatchReq seriesOrderTouristFeeAdjust = new SeriesOrderTouristFeeAdjustSaveBatchReq();
                    seriesOrderTouristFeeAdjust.setRelationId(singleRoomAdjustDTO.getId());
                    seriesOrderTouristFeeAdjust.setAmount(singleRoomAdjustDTO.getCostAmount().multiply(new BigDecimal(singleRoomAdjustDTO.getExchangeRate())).setScale(0, BigDecimal.ROUND_UP));
                    seriesOrderTouristFeeAdjust.setPlusType(singleRoomAdjustDTO.getAdjustType());
                    seriesOrderTouristFeeAdjust.setName(singleRoomAdjustDTO.getProjectName());
                    seriesOrderTouristFeeAdjust.setTouristId(touristId);
                    seriesOrderTouristFeeAdjust.setAdjustType(AdjustTypeCode.ADJUST.getCode());
                    seriesOrderTouristFeeAdjust.setOrderId(order.getId());
                    /*if (req.getMemberId() != null) {
                        seriesOrderTouristFeeAdjust.setUserId(req.getMemberId());
                    }*/
                    adjustSaveBatchReqList.add(seriesOrderTouristFeeAdjust);

                    singleRoomNum--;

                    //累计调整费用
                    if (Objects.equals(singleRoomAdjustDTO.getAdjustType(), PlusTypeCode.PLUS.getCode())) {
                        adjustmentCost = adjustmentCost.add(seriesOrderTouristFeeAdjust.getAmount());
                    } else if (Objects.equals(singleRoomAdjustDTO.getAdjustType(), PlusTypeCode.SUBTRACT.getCode())) {
                        adjustmentCost = adjustmentCost.subtract(seriesOrderTouristFeeAdjust.getAmount());
                    }
                }

                //应收=团费+代收+调整+其他
                totalReceivables = ((groupFee.add(collectionFee)).add(adjustmentCost)).add(otherAmount);
                //未收=应收-实收
                remainingReceivables = totalReceivables.subtract(totalPaidIn);

                SeriesOrderTouristInfoSaveBatchReq touristInfoSaveBatchReq = EntityUtil.copy(touristReq, SeriesOrderTouristInfoSaveBatchReq.class);
                touristInfoSaveBatchReq.setId(SnowflakeIdWorker.nextId());
                touristInfoSaveBatchReq.setOrderId(order.getId());
                touristInfoSaveBatchReq.setScheduleId(req.getScheduleId());
                touristInfoSaveBatchReq.setMainDataId(touristReq.getMainDataId());

                touristInfoSaveBatchReq.setTouristTypeName(touristReq.getTouristTypeName());
                touristInfoSaveBatchReq.setPayStatus(PayStatusCode.WAIT.getCode());
                touristInfoSaveBatchReq.setNoshow(LockStatusCode.NO.getCode());
                touristInfoSaveBatchReq.setLockStatus(LockStatusCode.NO.getCode());
                touristInfoSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                touristInfoSaveBatchReq.setGmtCreate(now);
                touristInfoSaveBatchReq.setGmtModified(now);
                if (StringUtils.isNotBlank(touristReq.getEnSurname()) && StringUtils.isNotBlank(touristReq.getEnName())) {
                    touristInfoSaveBatchReq.setEnName(touristReq.getEnName());
                    touristInfoSaveBatchReq.setEnSurname(touristReq.getEnSurname());
                    touristInfoSaveBatchReq.setEnFullname(touristReq.getEnSurname() + touristReq.getEnName());
                }

                /*if (req.getMemberId() != null) {
                    touristInfoSaveBatchReq.setCreateId(req.getMemberId());
                }*/
                touristInfoSaveBatchReq.setIsFullInfo(ISCode.YES.getCode());
                //订单统计
                touristInfoSaveBatchReq.setGroupFee(groupFee);
                touristInfoSaveBatchReq.setTotalReceivables(totalReceivables);
                touristInfoSaveBatchReq.setTotalPaidIn(totalPaidIn);
                touristInfoSaveBatchReq.setRefundAmount(refundAmount);
                touristInfoSaveBatchReq.setCollectionFee(collectionFee);
                touristInfoSaveBatchReq.setAdjustmentCost(adjustmentCost);
                touristInfoSaveBatchReq.setOtherAmount(otherAmount);
                touristInfoSaveBatchReq.setIsFullInfo(1);
                touristInfoSaveBatchReq.setReceiptedAmount(receiptedAmount);
                touristInfoSaveBatchReq.setRemainingReceivables(remainingReceivables);
                touristInfoSaveBatchReq.setIsReceiptCalculated(ISCode.NO.getCode());
                touristInfoSaveBatchReq.setBuyInsurance(ISCode.NO.getCode());
                // 保存代收费用json
                if (collectionFeeJsonList.size() > 0) {
                    touristInfoSaveBatchReq.setCollectionFeeJson(JSON.toJSONString(collectionFeeJsonList));
                }

                // 设置紧急联络人信息
                if (StringUtils.isNotEmpty(req.getEmergencyContactEnSurname()) && StringUtils.isNotEmpty(req.getEmergencyContactEnName())) {
                    touristInfoSaveBatchReq.setEmergencyContactName(req.getEmergencyContactEnSurname() + req.getEmergencyContactEnName());
                    touristInfoSaveBatchReq.setEmergencyMobileAreaCode(req.getEmergencyMobileAreaCode());
                    touristInfoSaveBatchReq.setEmergencyMobile(req.getEmergencyMobile());
                }

                // 签证信息
                List<SeriesOrderTouristInfoSaveBatchCertificateReq> certificateReqs = new ArrayList<>();
                List<ClientTouristCertificatesReq> passengerCertificatesList = touristReq.getPassengerCertificatesList();
                if (CollectionUtil.isNotEmpty(passengerCertificatesList)) {
                    for (ClientTouristCertificatesReq clientTouristCertificatesReq : passengerCertificatesList) {
                        SeriesOrderTouristInfoSaveBatchCertificateReq certificateReq = new SeriesOrderTouristInfoSaveBatchCertificateReq();
                        certificateReq.setCertificateValidDate(clientTouristCertificatesReq.getEffectiveTime());
                        certificateReq.setCertificateNumber(clientTouristCertificatesReq.getCertificatesNumber());
                        certificateReq.setCertificatePlace(clientTouristCertificatesReq.getAreaName());
                        certificateReq.setCertificatePlaceId(clientTouristCertificatesReq.getAreaId());
                        certificateReq.setCertificateType(clientTouristCertificatesReq.getCertificatesTypeName());
                        certificateReq.setCertificateTypeId(clientTouristCertificatesReq.getCertificatesTypeId());
                        certificateReqs.add(certificateReq);
                    }
                }
                touristInfoSaveBatchReq.setCertificateList(certificateReqs);
                touristInfoSaveBatchReqList.add(touristInfoSaveBatchReq);

                //团费
                orderGroupFee = orderGroupFee.add(groupFee);
                //应收
                orderTotalReceivables = orderTotalReceivables.add(totalReceivables);
                //实收
                orderTotalPaidIn = orderTotalPaidIn.add(totalPaidIn);
                //已退款
                orderRefundAmount = orderRefundAmount.add(refundAmount);
                //代收费用
                orderCollectionFee = orderCollectionFee.add(collectionFee);
                //调整费用
                orderAdjustmentCost = orderAdjustmentCost.add(adjustmentCost);
                //其他金额
                orderOtherAmount = orderOtherAmount.add(otherAmount);
                //已出单据金额
                orderReceiptedAmount = orderReceiptedAmount.add(receiptedAmount);
                //未收
                orderRemainingReceivables = orderRemainingReceivables.add(remainingReceivables);
            }

        } else if (Objects.equals(tripScheduleDTO.getCostSharingType(), CostSharingType.CUSTOM.getCode())) {
            //自定义
            TripCustomCostReq tripCustomCostReq = tripScheduleDTO.getTripCustomCostReq();
            List<TripCustomSalePriceReq> customSalePriceList = tripCustomCostReq.getCustomSalePriceList();

            List<SeriesTripDefaultCostCollectionReq> customCostCollectionList = tripCustomCostReq.getCostCollectionList();
            List<SeriesTripCustomFeeAdjustReq> customFeeAdjustList = tripCustomCostReq.getFeeAdjustList();

            for (ClientTouristInfoReq touristReq : req.getTouristList()) {
                //团费
                TripCustomSalePriceReq selectTripCustomSalePriceReq = null;
                A:
                for (TripCustomSalePriceReq tripCustomSalePriceReq : customSalePriceList) {
                    if (Objects.equals(tripCustomSalePriceReq.getMainDataId(), touristReq.getMainDataId())) {
                        if (Objects.equals(tripCustomSalePriceReq.getDateType(), DataType.WEEK.getCode())) {
                            for (Integer checkWeekDay : tripCustomSalePriceReq.getCheckWeekDays()) {
                                if (Objects.equals(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue(), checkWeekDay)) {
                                    selectTripCustomSalePriceReq = tripCustomSalePriceReq;
                                    break A;
                                }
                            }
                        } else if (Objects.equals(tripCustomSalePriceReq.getDateType(), DataType.DATE.getCode())) {
                            if (tripScheduleDTO.getDepartureDate().compareTo(tripCustomSalePriceReq.getDateBegin()) >= 0
                                    && tripScheduleDTO.getDepartureDate().compareTo(tripCustomSalePriceReq.getDateEnd()) <= 0) {
                                selectTripCustomSalePriceReq = tripCustomSalePriceReq;
                                break A;
                            }
                        }
                    }
                }
                if (selectTripCustomSalePriceReq == null) {
                    throw new BusinessException(SystemError.SYS_411);
                }

                long touristId = touristReq.getMainDataId();

                //团费
                BigDecimal groupCustomerPrice = selectTripCustomSalePriceReq.getGroupCustomerPrice();
                BigDecimal groupFee = feeIncrease(adjustType, amount, groupCustomerPrice);
                //应收
                BigDecimal totalReceivables = new BigDecimal(0);
                //实收
                BigDecimal totalPaidIn = new BigDecimal(0);
                //已退款
                BigDecimal refundAmount = new BigDecimal(0);
                //代收费用
                BigDecimal collectionFee = new BigDecimal(0);
                //调整费用
                BigDecimal adjustmentCost = new BigDecimal(0);
                //其他金额
                BigDecimal otherAmount = new BigDecimal(0);
                //已出单据金额
                BigDecimal receiptedAmount = new BigDecimal(0);
                //未收
                BigDecimal remainingReceivables = new BigDecimal(0);
                // 代收费用项
                List<TouristCollectionFeeJson> collectionFeeJsonList = new ArrayList<>();

                if (CollectionUtil.isNotEmpty(customCostCollectionList)) {
                    for (SeriesTripDefaultCostCollectionReq seriesTripDefaultCostCollectionReq : customCostCollectionList) {
                        //判断代收费用中是否有相同游客类型的代收费用
                        for (SeriesTripDefaultCostCollectionTypeReq typeDTO : seriesTripDefaultCostCollectionReq.getCostCollectionTypeList()) {
                            if (Objects.equals(typeDTO.getTouristTypeId(), touristReq.getMainDataId())) {
                                // 代收费用项
                                TouristCollectionFeeJson collectionFeeJson = new TouristCollectionFeeJson();
                                collectionFeeJson.setProjectName(seriesTripDefaultCostCollectionReq.getProjectName());
                                collectionFeeJson.setMainDataId(seriesTripDefaultCostCollectionReq.getMainDataId());
                                collectionFeeJson.setAdjustType(PlusTypeCode.PLUS.getCode());
                                collectionFeeJson.setTotalAmount(typeDTO.getTotalAmount().multiply(new BigDecimal(seriesTripDefaultCostCollectionReq.getExchangeRate())).setScale(0, BigDecimal.ROUND_UP));
                                collectionFeeJsonList.add(collectionFeeJson);
                                //累计代收费用
                                collectionFee = collectionFee.add(collectionFeeJson.getTotalAmount());
                            }
                        }
                    }
                }

                //其他费用

                if (singleRoomNum > 0) {
                    //单房差
                    SeriesTripCustomFeeAdjustReq singleRoomCustomFeeAdjustReq = null;
                    CustomCostReq singleRoomCustomCostReq = null;
                    B:
                    if (CollectionUtil.isNotEmpty(customFeeAdjustList)) {
                        for (SeriesTripCustomFeeAdjustReq seriesTripCustomFeeAdjustReq : customFeeAdjustList) {
                            if (Objects.equals(seriesTripCustomFeeAdjustReq.getMainDataId(), Constants.SINGLE_ROOM_ID)) {
                                for (CustomCostReq customCostReq : seriesTripCustomFeeAdjustReq.getCustomCostList()) {
                                    if (Objects.equals(customCostReq.getMainDataId(), touristReq.getMainDataId())) {
                                        if (Objects.equals(customCostReq.getDateType(), DataType.WEEK.getCode())) {
                                            for (Integer checkWeekDay : customCostReq.getCheckWeekDays()) {
                                                if (Objects.equals(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue(), checkWeekDay)) {
                                                    singleRoomCustomFeeAdjustReq = seriesTripCustomFeeAdjustReq;
                                                    singleRoomCustomCostReq = customCostReq;
                                                    break B;
                                                }
                                            }
                                        } else if (Objects.equals(customCostReq.getDateType(), DataType.DATE.getCode())) {
                                            if (tripScheduleDTO.getDepartureDate().compareTo(customCostReq.getDateBegin()) >= 0
                                                    && tripScheduleDTO.getDepartureDate().compareTo(customCostReq.getDateEnd()) <= 0) {
                                                singleRoomCustomFeeAdjustReq = seriesTripCustomFeeAdjustReq;
                                                singleRoomCustomCostReq = customCostReq;
                                                break B;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    //调整费用
                    if (singleRoomCustomFeeAdjustReq != null && singleRoomCustomCostReq != null) {
                        SeriesOrderTouristFeeAdjustSaveBatchReq seriesOrderTouristFeeAdjust = new SeriesOrderTouristFeeAdjustSaveBatchReq();
                        seriesOrderTouristFeeAdjust.setRelationId(singleRoomCustomFeeAdjustReq.getId());
                        seriesOrderTouristFeeAdjust.setAmount(singleRoomCustomCostReq.getPrice().multiply(new BigDecimal(singleRoomCustomFeeAdjustReq.getExchangeRate())).setScale(0, BigDecimal.ROUND_UP));
                        seriesOrderTouristFeeAdjust.setPlusType(singleRoomCustomFeeAdjustReq.getAdjustType());
                        seriesOrderTouristFeeAdjust.setName(singleRoomCustomFeeAdjustReq.getProjectName());
                        seriesOrderTouristFeeAdjust.setTouristId(touristId);
                        seriesOrderTouristFeeAdjust.setAdjustType(AdjustTypeCode.ADJUST.getCode());
                        seriesOrderTouristFeeAdjust.setOrderId(order.getId());
                        adjustSaveBatchReqList.add(seriesOrderTouristFeeAdjust);

                        singleRoomNum--;

                    /*if (req.getMemberId() != null) {
                        seriesOrderTouristFeeAdjust.setUserId(req.getMemberId());
                    }*/

                        //累计调整费用
                        if (Objects.equals(singleRoomCustomFeeAdjustReq.getAdjustType(), PlusTypeCode.PLUS.getCode())) {
                            adjustmentCost = adjustmentCost.add(seriesOrderTouristFeeAdjust.getAmount());
                        } else if (Objects.equals(singleRoomCustomFeeAdjustReq.getAdjustType(), PlusTypeCode.SUBTRACT.getCode())) {
                            adjustmentCost = adjustmentCost.subtract(seriesOrderTouristFeeAdjust.getAmount());
                        }
                    }
                }

                //应收=团费+代收+调整+其他
                totalReceivables = ((groupFee.add(collectionFee)).add(adjustmentCost)).add(otherAmount);
                //未收=应收-实收
                remainingReceivables = totalReceivables.subtract(totalPaidIn);

                SeriesOrderTouristInfoSaveBatchReq touristInfoSaveBatchReq = new SeriesOrderTouristInfoSaveBatchReq();
                touristInfoSaveBatchReq.setId(SnowflakeIdWorker.nextId());
                touristInfoSaveBatchReq.setOrderId(order.getId());
                touristInfoSaveBatchReq.setScheduleId(req.getScheduleId());
                touristInfoSaveBatchReq.setMainDataId(touristReq.getMainDataId());
                touristInfoSaveBatchReq.setTouristTypeName(touristReq.getTouristTypeName());
                touristInfoSaveBatchReq.setChannelId(req.getChannelId());
                touristInfoSaveBatchReq.setPayStatus(PayStatusCode.WAIT.getCode());
                touristInfoSaveBatchReq.setNoshow(LockStatusCode.NO.getCode());
                touristInfoSaveBatchReq.setLockStatus(LockStatusCode.NO.getCode());
                touristInfoSaveBatchReq.setIsDeleted(IsDeletedCode.NO.getCode());
                touristInfoSaveBatchReq.setIsFullInfo(1);
                touristInfoSaveBatchReq.setGmtCreate(now);
                touristInfoSaveBatchReq.setGmtModified(now);
                if (StringUtils.isNotBlank(touristReq.getEnSurname()) && StringUtils.isNotBlank(touristReq.getEnName())) {
                    touristInfoSaveBatchReq.setEnName(touristReq.getEnName());
                    touristInfoSaveBatchReq.setEnSurname(touristReq.getEnSurname());
                    touristInfoSaveBatchReq.setEnFullname(touristReq.getEnSurname() + touristReq.getEnName());
                }

                // 保存代收费用json
                if (collectionFeeJsonList.size() > 0) {
                    touristInfoSaveBatchReq.setCollectionFeeJson(JSON.toJSONString(collectionFeeJsonList));
                }
                /*if (req.getMemberId() != null) {
                    touristInfoSaveBatchReq.setUserId(req.getMemberId());
                }*/

                // 设置紧急联络人信息
                if (StringUtils.isNotEmpty(req.getEmergencyContactEnSurname()) && StringUtils.isNotEmpty(req.getEmergencyContactEnName())) {
                    touristInfoSaveBatchReq.setEmergencyContactName(req.getEmergencyContactEnSurname() + req.getEmergencyContactEnName());
                    touristInfoSaveBatchReq.setEmergencyMobileAreaCode(req.getEmergencyMobileAreaCode());
                    touristInfoSaveBatchReq.setEmergencyMobile(req.getEmergencyMobile());
                }

                touristInfoSaveBatchReq.setIsFullInfo(ISCode.NO.getCode());
                //订单统计
                touristInfoSaveBatchReq.setGroupFee(groupFee);
                touristInfoSaveBatchReq.setTotalReceivables(totalReceivables);
                touristInfoSaveBatchReq.setTotalPaidIn(totalPaidIn);
                touristInfoSaveBatchReq.setRefundAmount(refundAmount);
                touristInfoSaveBatchReq.setCollectionFee(collectionFee);
                touristInfoSaveBatchReq.setAdjustmentCost(adjustmentCost);
                touristInfoSaveBatchReq.setOtherAmount(otherAmount);
                touristInfoSaveBatchReq.setReceiptedAmount(receiptedAmount);
                touristInfoSaveBatchReq.setRemainingReceivables(remainingReceivables);
                touristInfoSaveBatchReq.setIsReceiptCalculated(ISCode.NO.getCode());
                touristInfoSaveBatchReq.setBuyInsurance(ISCode.NO.getCode());
                touristInfoSaveBatchReq.setMobileAreaCode(touristReq.getMobileAreaCode());
                touristInfoSaveBatchReq.setMobile(touristReq.getMobile());
                touristInfoSaveBatchReqList.add(touristInfoSaveBatchReq);

                // 团费
                orderGroupFee = orderGroupFee.add(groupFee);
                // 应收
                orderTotalReceivables = orderTotalReceivables.add(totalReceivables);
                // 实收
                orderTotalPaidIn = orderTotalPaidIn.add(totalPaidIn);
                // 已退款
                orderRefundAmount = orderRefundAmount.add(refundAmount);
                // 代收费用
                orderCollectionFee = orderCollectionFee.add(collectionFee);
                // 调整费用
                orderAdjustmentCost = orderAdjustmentCost.add(adjustmentCost);
                // 其他金额
                orderOtherAmount = orderOtherAmount.add(otherAmount);
                // 已出单据金额
                orderReceiptedAmount = orderReceiptedAmount.add(receiptedAmount);
                // 未收
                orderRemainingReceivables = orderRemainingReceivables.add(remainingReceivables);

            }
        }
        // 积分优惠扣减
        if (ObjectUtils.isNotEmpty(req.getScore())) {
            int dscount = req.getScore() / 100;
            orderTotalReceivables = orderTotalReceivables.subtract(new BigDecimal(dscount));
        }

        // 验价
        BigDecimal orderAmount = req.getOrderAmount();
        if (orderTotalReceivables.compareTo(orderAmount) != 0) {
            // 异步更新缓存
            CompletableFuture.runAsync(() -> {
                seriesTripAppService.updateTripCache(new TripCacheUpdateReq().setIds(Arrays.asList(tripId)));
            });
            throw new BusinessException(SystemError.TOUR_ORDER_30032);
        }

        // 锁位
        iSeriesTripScheduleService.updateScheduleNum(req.getScheduleId(), totalPeopleNumber);

        // 批量新增旅客
        if (touristInfoSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristInfoService.saveBatch(touristInfoSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_437);
            }
        }

        // 批量新增其他费用
        if (otherFeeSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristOtherFeeService.saveBatch(otherFeeSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_437);
            }
        }

        // 批量新增调整费用
        if (adjustSaveBatchReqList.size() > 0) {
            Boolean batch = iSeriesOrderTouristFeeAdjustService.saveBatch(adjustSaveBatchReqList);
            if (!batch) {
                throw new BusinessException(SystemError.SYS_437);
            }
        }

        // 用户id
        if (req.getUserId() != null) {
            order.setUserId(req.getUserId());
        }
        order.setGmtCreate(now);
        order.setGmtModified(now);
        LocalDateTime payEndTime = now.plusMinutes(30L);
        order.setPayEndTime(payEndTime);
        // 查詢編號
        String queryNumber = CharUtil.getNumber(4, 4);
        order.setQueryNumber(queryNumber);
        order.setIsDeleted(0);
        order.setIsPay(0);
        order.setGmtModified(now);
        order.setPlusTouristType(PlusTouristTypeCode.DOWN.getCode());
        order.setPlaceOrderStatus(PlaceOrderStatusCode.WAIT_CONFIRM.getCode());
        order.setTotalPrice(orderTotalReceivables);
        order.setOrderSource(appReq.getOrderSource());
        order.setReceiptHeader(req.getReceiptHeader());
        // 联络人
        order.setContactEnName(req.getContactEnName());
        order.setContactEnSurname(req.getContactEnSurname());
        order.setContactEmail(req.getContactEmail());
        order.setContactGender(req.getContactGender());
        TelephonesJson telephonesJson = new TelephonesJson();
        telephonesJson.setPhoneNo(req.getPhone());
        telephonesJson.setAreaCode(req.getPhoneCode());
        order.setContactTelephones(JSON.toJSONString(telephonesJson));

        // 如果有使用积分，进行会员积分扣减
        if (ObjectUtils.isNotEmpty(req.getScore())) {
            TransactionIntegralCommonReq transactionIntegralCommonReq = new TransactionIntegralCommonReq();
            transactionIntegralCommonReq.setMemberId(userDTO.getMemberId());
            transactionIntegralCommonReq.setOrderNumber(order.getOrderNumber());
            transactionIntegralCommonReq.setReceivableAmount(orderTotalReceivables);
            transactionIntegralCommonReq.setTransactionType(2);
            transactionIntegralCommonReq.setUsePoints(new BigDecimal(req.getScore()));
            if (businessType == 1) {
                transactionIntegralCommonReq.setSystemBusinessType(SystemBusinessType.OUTBOUND_TRAVEL.getCode());
            } else {
                transactionIntegralCommonReq.setSystemBusinessType(SystemBusinessType.INBOUND_TRAVEL.getCode());
            }
            transactionIntegralCommonReq.setCurrency(Currency.HKD.getCurrency());
            transactionIntegralCommonReq.setUserId(order.getUserId());
            iStarVipBusinessService.transactionIntegralCommon(transactionIntegralCommonReq);

            // 保存订单会员信息
            order.setMemberId(userDTO.getMemberId());
            order.setMemberEmail(userDTO.getEmail());
            order.setMemberLevel(userDTO.getMemberLevel().toString());
            order.setMemberScore(score.toString());
            order.setMemberMobile(userDTO.getContactMobileAreaCode() + "-" + userDTO.getContactNumber());
            order.setMemberType(MemberType.STAR_CLUB_MEMBER.getCode());
            order.setMemberName(userDTO.getEnFullname());
            order.setUseScore(req.getScore().toString());
        }

        // 计算可获得积分
        int obtainByType = CalcIntegralUtil.getObtainByType(businessType, ObjectUtils.isEmpty(userDTO) ? MemberLevel.SILVER.getLevel() : userDTO.getMemberLevel(), orderTotalReceivables);
        order.setPoint(obtainByType);

        //新增订单
        boolean save = save(order);
        // 启动定时任务
        startScheduleTask(order.getId());

        // 新增订单统计
        SeriesOrderAmountStatistics statistics = new SeriesOrderAmountStatistics();
        statistics.setId(SnowflakeIdWorker.nextId());
        statistics.setScheduleId(req.getScheduleId());
        statistics.setOrderId(order.getId());
        statistics.setTotalTourFee(orderGroupFee);
        statistics.setTotalReceivables(orderTotalReceivables);
        statistics.setTotalPaidIn(orderTotalPaidIn);
        statistics.setRefundAmount(orderRefundAmount);
        statistics.setCollectionFee(orderCollectionFee);
        statistics.setAdjustmentCost(orderAdjustmentCost);
        statistics.setOtherAmount(orderOtherAmount);
        statistics.setReceiptedAmount(orderReceiptedAmount);
        statistics.setRemainingReceivables(orderRemainingReceivables);
        int insert = seriesOrderAmountStatisticsMapper.insert(statistics);
        if (!save || insert <= 0) {
            throw new BusinessException(SystemError.SYS_437);
        }

        // 在return前发送订单数据到个人中心
        sendOrderToAppUser(order.getId());
        return Result.success(order.getId());
    }

    /**
     * 下单完成后调用任务执行如果未付款则超时失效订单操作
     *
     * @param id
     */
    public void startScheduleTask(Long id) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", id);
        // 延迟时间,单位毫秒,1800000L=30分钟后执行
        long delayMS = 1000 * 60 * 30;
        log.info("【旅行团订单-提交订单】提交订单成功，启动定时任务:{},appName:{},time:{}", domain, appName, delayMS);
        try {
            OhMyClient taskClient = new OhMyClient(domain, appName, password);
            ResultDTO<Long> resultTask = taskClient.runJob(jobId, jsonObject.toJSONString(), delayMS);
            if (resultTask.isSuccess()) {
                // 任务执行成功,过期时间*2是防止任务启动时redis数据已过期
                redisTemplate.opsForValue().set(RedisConstants.ORDER_INSTANCELD_KEY + id, resultTask.getData(), delayMS * 2, TimeUnit.MILLISECONDS);
            }
        } catch (Exception e) {
            log.error("【旅行团订单-提交订单】 启动定时任务失败", e);
            /* throw new BusinessException(SystemError.TOUR_ORDER_30038);*/
        }
    }

    /**
     * 获取销售人并生成销售编号
     *
     * @param order
     * @param companyType
     */
    private void getSaleMan(SeriesOrder order, String companyType, LocalDateTime now, Integer businessType) {
        DispatchOrderRuleGetUserReq dispatchOrderRuleGetUserReq = new DispatchOrderRuleGetUserReq();
        dispatchOrderRuleGetUserReq.setBusinessTypeId(businessType);
        dispatchOrderRuleGetUserReq.setCompanyType(companyType);
        Result<Long> result = dispatchOrderRuleService.getDispatchUserId(dispatchOrderRuleGetUserReq);
        if (!result.isSuccess()) {
            log.error("【旅行团APP-提交订单】获取销售人失败:{},msg:{}", result.getCode(), result.getMsg());
            throw new BusinessException(SystemError.getDefined(result.getCode()));
        }
        UserDTO saleUser = sysUserService.queryCacheUser(result.getData());
        String orderNumber = generatorOrderNumber(saleUser, now);
        order.setOrderNumber(orderNumber);
        order.setSalesmanId(saleUser.getId());
        order.setCreateId(saleUser.getId());
        order.setSalesmanName(saleUser.getFullName());
    }

    /**
     * 生成旅行团销售编号=T+部门代码+员工编号+年后2位+月日4位+3位随机数字
     *
     * @param userDTO
     * @return
     */
    public static String generatorOrderNumber(UserDTO userDTO, LocalDateTime nowLocalDateTime) {
        String employeeNumber = userDTO.getEmployeeNumber();
        String deptCode = userDTO.getDeptCode();
        String date = DateUtil.fmt(nowLocalDateTime, "yyMMdd");
        String randomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 100));
        StringBuilder orderNumberSb = new StringBuilder();
        orderNumberSb.append("T").append(deptCode).append(employeeNumber).append(date).append(randomNumber);
        return orderNumberSb.toString().toUpperCase();
    }

    /**
     * 取消订单（C端）
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result cancel2(ClientOrderCancelReq req) {
        SeriesOrder order = getById(req.getOrderId());
        if (order == null || Objects.equals(order.getIsDeleted(), IsDeletedCode.YES.getCode())) {
            throw new BusinessException(SystemError.TOUR_ORDER_30006);
        }

        SeriesTripScheduleDTO tripSchedule = iSeriesTripScheduleService.getTripScheduleId(order.getScheduleId());
        if (tripSchedule == null) {
            throw new BusinessException(SystemError.TOUR_30012);
        }

        // 未支付直接取消
        if (Objects.equals(order.getIsPay(), 0)) {
            // 更新团锁位人数
            UpdateScheduleNumReq updateScheduleNumReq = new UpdateScheduleNumReq();
            updateScheduleNumReq.setId(order.getScheduleId());
            updateScheduleNumReq.setNum(order.getTotalPeople());
            iSeriesTripScheduleService.updateScheduleNum(updateScheduleNumReq);

            // 更新订单状态信息
            order.setOrderStatus(TourOrderStatusCode.CANCEL_2.getOldCode());
            int i = baseMapper.updateById(order);
            if (i > 0) {
                return Result.success("订单取消成功");
            } else {
                throw new BusinessException(SystemError.SYS_437);
            }
        }

        // 已支付发起审批
        if (Objects.equals(order.getIsPay(), 1)) {
            if (ObjectUtils.isEmpty(req.getQuitReasonId())) {
                throw new BusinessException(SystemError.TOUR_ORDER_30036);
            }

            order.setRefundStatus(TourRefundStatusCode.PENDING_REFUND.getOldCode());
            order.setOrderStatus(TourOrderStatusCode.CANCEL_2.getOldCode());

            // 更新订单状态信息
            int num = baseMapper.updateById(order);
            if (num < 0) {
                throw new BusinessException(SystemError.SYS_437);
            }

            // 获取订单旅客列表
            QueryWrapper<SeriesOrderTouristInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("order_id", order.getId());
            queryWrapper.eq("is_deleted", IsDeletedCode.NO.getCode());
            List<SeriesOrderTouristInfo> touristInfoList = seriesOrderTouristInfoMapper.selectList(queryWrapper);
            if (CollectionUtils.isNotEmpty(touristInfoList)) {
                // 退团扣费规则
                BigDecimal deductionAmount = BigDecimal.ZERO;
                SeriesTripScheduleTeamRuleDTO teamRuleDTO = tripSchedule.getSeriesTripScheduleTeamRuleDTO();
                MainDataDeductionRulesDTO rulesDTO = null;

                // 当前距离出发日期多少天
                long remainDay = LocalDate.now().until(tripSchedule.getDepartureDate(), ChronoUnit.DAYS);
                if (teamRuleDTO != null && teamRuleDTO.getDeductionRulesId() != null) {
                    MainDataDeductionRulesIdReq rulesIdReq = new MainDataDeductionRulesIdReq();
                    rulesIdReq.setId(teamRuleDTO.getDeductionRulesId());
                    try {
                        rulesDTO = deductionRulesService.query(rulesIdReq);
                    } catch (Exception e) {
                        throw new BusinessException(SystemError.MAINDATA_4023);
                    }
                }

                // 发起旅客批量退团审批
                List<SeriesOrderTouristQuit> quitList = new ArrayList<>();
                for (SeriesOrderTouristInfo touristInfo : touristInfoList) {
                    SeriesOrderTouristQuit quit = new SeriesOrderTouristQuit();
                    quit.setId(SnowflakeIdWorker.nextId());
                    quit.setOrderId(order.getId());
                    quit.setScheduleId(order.getScheduleId());
                    quit.setTouristId(touristInfo.getId());
                    quit.setCollectionFee(touristInfo.getCollectionFee());
                    // 退款金额 港幣金額=其他貨幣金額×對應的門市匯率
                    BigDecimal quitRefundAmount = touristInfo.getTotalPaidIn();
                    // 查询优惠金额
                    BigDecimal discountAmount = new BigDecimal(0);
                    QueryWrapper<SeriesOrderCollection> queryWrapper3 = new QueryWrapper<>();
                    queryWrapper3.lambda().eq(SeriesOrderCollection::getOrderId, req.getOrderId());
                    queryWrapper3.lambda().eq(SeriesOrderCollection::getTouristId, touristInfo.getId());
                    queryWrapper3.lambda().and(object -> object.eq(SeriesOrderCollection::getCollectionWayId, CollectionRefundWayIdCode.OPERATE_PROMOTION.getCode())
                            .or().eq(SeriesOrderCollection::getCollectionWayId, CollectionRefundWayIdCode.POINTS.getCode()));
                    queryWrapper3.lambda().eq(SeriesOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode());
                    List<SeriesOrderCollection> collectionList = seriesOrderCollectionMapper.selectList(queryWrapper3);
                    for (SeriesOrderCollection collection : collectionList) {
                        discountAmount = discountAmount.add(collection.getPaidInAmount());
                    }
                    quit.setRefundAmount(quitRefundAmount);
                    quit.setDiscountAmount(discountAmount);

                    // 退团扣费
                    if (rulesDTO != null && rulesDTO.getRulesDetailsDTOList() != null && rulesDTO.getRulesDetailsDTOList().size() > 0) {
                        for (int i = rulesDTO.getRulesDetailsDTOList().size(); i > 0; i--) {
                            MainDataDeductionRulesDetailsDTO detailsDTO = rulesDTO.getRulesDetailsDTOList().get(i - 1);
                            if (remainDay > detailsDTO.getBeforeDepartureDays()) {
                                if (detailsDTO.getDeductionRefundType().intValue() == NumberConstant.TWO.getValue()) {
                                    // 部分退
                                    if (detailsDTO.getDeductionAmountType().intValue() == NumberConstant.ONE.getValue()) {
                                        // 固定值
                                        deductionAmount = detailsDTO.getDeductionAmount();
                                    } else {
                                        // 百分比
                                        deductionAmount = quitRefundAmount.multiply(detailsDTO.getDeductionAmount().divide(new BigDecimal(100))).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                                    }
                                    break;
                                }
                            }
                        }
                    }

                    quit.setDeductionAmount(deductionAmount);
                    quit.setQuitReasonId(req.getQuitReasonId());
                    quit.setQuitReason(req.getQuitReason());
                    quit.setRemark(req.getRemark());

                    // 收全款记录
                    QueryWrapper<SeriesOrderCollection> queryWrapper2 = new QueryWrapper<>();
                    queryWrapper2.lambda().eq(SeriesOrderCollection::getOrderId, req.getOrderId());
                    queryWrapper2.lambda().eq(SeriesOrderCollection::getTouristId, touristInfo.getId());
                    queryWrapper2.lambda().eq(SeriesOrderCollection::getCollectionTypeId, CollectionTypeIdCode.FULL.getCode());
                    queryWrapper2.lambda().eq(SeriesOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode());
                    SeriesOrderCollection collection = seriesOrderCollectionMapper.selectOne(queryWrapper2);
                    if (collection != null) {
                        quit.setRefundTypeId(collection.getCollectionTypeId());
                        quit.setRefundType(collection.getCollectionType());
                        quit.setRefundAccount(collection.getPayer());
                        quit.setCurrencyTypeId(collection.getCurrencyTypeId());
                        quit.setCurrencyType(collection.getCurrencyType());
                        quit.setExchangeRate(collection.getExchangeRate());
                        quit.setCurrencyRefundAmount(collection.getCurrencyPaidInAmount());
                    }
                    quit.setGmtCreate(LocalDateTime.now());
                    quit.setIsDeleted(0);

                    // 发起审批
                    // 获取业务类型
                    Integer businessType = seriesTripService.findTripBusinessTypeById(order.getTripId());
                    Result<ApprovalStartDTO> result = null;
                    Long userId = 0L;
                    if (StringUtils.isNotEmpty(order.getMemberId())) {
                        String memberId = order.getMemberId();
                        userId = Long.parseLong(memberId);
                    } else {
                        userId = order.getSalesmanId();
                    }
                    if (businessType == SystemBusinessType.OUTBOUND_TRAVEL.getCode()) {
                        result = iSysApprovalService.start(SystemBusinessType.OUTBOUND_TRAVEL.getCode(), SysApprovalType.LEAVE_OUTTRA.getCode(), quit.getId(), userId, null, null);
                    } else {
                        result = iSysApprovalService.start(SystemBusinessType.INBOUND_TRAVEL.getCode(), SysApprovalType.LEAVE_INTRA.getCode(), quit.getId(), userId, null, null);
                    }
                    if (result == null || result.getCode() != 0 || result.getData() == null) {
                        throw new BusinessException(SystemError.SYS_437);
                    }
                    quit.setApprovalId(result.getData().getApprovalId());
                    quit.setRefundStatus(2);
                    quitList.add(quit);
                }

                // 批量新增退团记录
                if (quitList.size() > 0) {
                    Integer batch = seriesOrderTouristQuitMapper.insertBatchSomeColumn(quitList);
                    if (batch < quitList.size()) {
                        throw new BusinessException(SystemError.SYS_437);
                    }
                }
            }
        }

        // 更新个人中心订单状态
        updateStatusToAppUser(order.getId());
        return Result.success("订单取消申请已提交");
    }

    /**
     * 支付回调
     *
     * @param notifyConsume
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result payment(NotifyConsumeReq notifyConsume) {
        log.info("【旅行团支付-支付回调】, 入参data：{}", notifyConsume);
        ClientOrderPaySuccessReq req = new ClientOrderPaySuccessReq();
        req.setOrderId(Long.valueOf(notifyConsume.getOrderNumber()));
        PaymentMethod byCode = PaymentMethod.getByCode(notifyConsume.getPaymentMethod());
        req.setCollectionWay(byCode.getName());
        req.setCollectionWayId(byCode.getPayRefundMethodId());
        Integer orderStatus = notifyConsume.getOrderStatus();

        SeriesOrder order = getById(req.getOrderId());
        if (order == null || Objects.equals(order.getIsDeleted(), IsDeletedCode.YES.getCode())) {
            throw new BusinessException(SystemError.TOUR_ORDER_30006);
        }

        if (Objects.equals(order.getIsPay(), IsPayStatusCode.RECEIVED_PAYMENT.getOldCode())) {
            //已支付
            throw new BusinessException(SystemError.TOUR_ORDER_30015);
        }

        // 支付截止时间判断
        LocalDateTime now = LocalDateTime.now();
        if (!now.isBefore(order.getPayEndTime())) {
            // 修改订单：已超时取消
            order.setOrderStatus(TourOrderStatusCode.CANCEL_3.getOldCode());
            boolean update = updateById(order);
            if (!update) {
                throw new BusinessException(SystemError.SYS_437);
            }
            log.info("【旅行团支付-支付回调】, 超时, 支付状态 {},支付时间:{},支付截止时间：{}", orderStatus, now, order.getPayEndTime());
            return Result.failed(new BusinessException(SystemError.TOUR_ORDER_30016));
        }

        if (orderStatus.intValue() == PayOrderStatus.UNPAID.getStatus()) {
            log.info("【旅行团支付-支付回调】, 未支付, 支付状态 data：{}", orderStatus);
            return Result.success(req.getOrderId());
        }

        if (orderStatus.intValue() == PayOrderStatus.PAYMENT_ERROR.getStatus()) {
            log.info("【旅行团支付-支付回调】, 支付失败, 支付状态 data：{}", orderStatus);
            order.setPayTime(now);
            order.setOrderStatus(orderStatus);
            boolean update = updateById(order);
            if (!update) {
                throw new BusinessException(SystemError.SYS_437);
            }
            return Result.success(req.getOrderId());
        }

        // 获取业务类型
        Integer businessType = seriesTripService.findTripBusinessTypeById(order.getTripId());

        if (orderStatus.intValue() == PayOrderStatus.FULFIL.getStatus()) {
            log.info("【旅行团支付-支付回调】, 支付成功, 支付状态 data：{}", orderStatus);
            SeriesTripScheduleDTO tripSchedule = iSeriesTripScheduleService.getTripScheduleId(order.getScheduleId());
            if (tripSchedule == null) {
                throw new BusinessException(SystemError.TOUR_30012);
            }
            order.setIsPay(IsPayStatusCode.RECEIVED_PAYMENT.getOldCode());
            order.setOrderStatus(TourOrderStatusCode.CANCEL_0.getOldCode());
            order.setPayTime(now);

            boolean flag = updateById(order);
            if (!flag) {
                throw new BusinessException(SystemError.SYS_437);
            }

            // 更新订单统计信息
            SeriesOrderAmountStatistics seriesOrderAmountStatistics = seriesOrderAmountStatisticsMapper.selectByOrderId(order.getId());
            seriesOrderAmountStatistics.setRemainingReceivables(BigDecimal.ZERO);
            seriesOrderAmountStatistics.setTotalPaidIn(seriesOrderAmountStatistics.getTotalReceivables());
            seriesOrderAmountStatisticsMapper.updateById(seriesOrderAmountStatistics);

            //查询订单旅客列表
            List<SeriesOrderTouristInfo> touristInfoList = seriesOrderTouristInfoMapper.selectList(
                    Wrappers.<SeriesOrderTouristInfo>lambdaQuery()
                            .eq(SeriesOrderTouristInfo::getOrderId, order.getId())
                            .eq(SeriesOrderTouristInfo::getIsDeleted, IsDeletedCode.NO.getCode())
            );

            if (CollectionUtils.isNotEmpty(touristInfoList)) {
                // 财务收款数据
                List<BillAddCollectionReq> billAddCollectionReqs = new ArrayList<>();
                for (SeriesOrderTouristInfo touristInfo : touristInfoList) {
                    // 更新旅客
                    touristInfo.setTotalPaidIn(touristInfo.getTotalReceivables());
                    touristInfo.setRemainingReceivables(BigDecimal.ZERO);
                    touristInfo.setPayStatus(PayStatusCode.FULL_PAYED.getCode());
                    int update = seriesOrderTouristInfoMapper.updateById(touristInfo);
                    if (update <= 0) {
                        throw new BusinessException(SystemError.SYS_437);
                    }
                    // 新增收款记录
                    SeriesOrderCollection collection = new SeriesOrderCollection();
                    collection.setId(SnowflakeIdWorker.nextId());
                    collection.setOrderId(order.getId());
                    collection.setScheduleId(order.getScheduleId());
                    collection.setTouristId(touristInfo.getId());
                    collection.setIsPos(0);
                    String collectionNumber = "SKD" + now.format(DateTimeFormatter.ofPattern(Utils.yyMMddHHmmss)) + Utils.getRandom2();
                    collection.setCollectionNumber(collectionNumber);
                    collection.setTotalReceivables(touristInfo.getTotalReceivables());
                    collection.setPaidInAmount(touristInfo.getTotalPaidIn());
                    MainDataCurrencyUpdateStatusReq currencyReq = new MainDataCurrencyUpdateStatusReq();
                    currencyReq.setId(CurrencyIdCode.HKD.getCode());
                    Result<MainDataCurrencyQueryDTO> result = iMainDataCurrencyService.query(currencyReq);
                    if (result != null && result.getCode() == 0 && result.getData() != null) {
                        MainDataCurrencyQueryDTO currency = result.getData();
                        collection.setCurrencyType(currency.getCurrencyCode());
                        collection.setExchangeRate(currency.getMarketExchangeRate());
                    }
                    collection.setCurrencyTypeId(CurrencyIdCode.HKD.getCode());
                    collection.setCollectionTypeId(CollectionTypeIdCode.FULL.getCode());
                    collection.setCollectionType(CollectionTypeIdCode.FULL.getMsg());
                    collection.setCollectionWayId(req.getCollectionWayId());
                    collection.setCollectionWay(req.getCollectionWay());
                    collection.setPayer(touristInfoList.get(0).getEnFullname());
                    collection.setPayerId(touristInfoList.get(0).getId());
                    collection.setIsPrint(0);
                    collection.setStatus(notifyConsume.getOrderStatus());
                    collection.setGmtCreate(now);
                    collection.setCurrencyPaidInAmount(touristInfo.getTotalPaidIn());
                    collection.setIsDeleted(0);
                    // 新增收款记录
                    int insert = seriesOrderCollectionMapper.insert(collection);
                    if (insert <= 0) {
                        throw new BusinessException(SystemError.SYS_437);
                    }
                    // 财务收款开始
                    BillAddCollectionReq billAddCollectionReq = new BillAddCollectionReq();
                    billAddCollectionReq.setBillNumber(collection.getCollectionNumber());
                    billAddCollectionReq.setBusinessType(businessType);
                    billAddCollectionReq.setCollectionWayId(collection.getCollectionWayId());
                    billAddCollectionReq.setCollectionWayName(collection.getCollectionWay());
                    billAddCollectionReq.setCollectionTypeId(collection.getCollectionTypeId());
                    billAddCollectionReq.setCollectionTypeName(collection.getCollectionType());
                    billAddCollectionReq.setCollectionAmount(collection.getPaidInAmount());
                    billAddCollectionReq.setCurrencyId(collection.getCurrencyTypeId());
                    billAddCollectionReq.setExchangeRate(collection.getExchangeRate().doubleValue());
                    billAddCollectionReq.setCurrencyName(collection.getCurrencyType());
                    billAddCollectionReq.setCollectionTime(now);
                    //todo  收款json需要处理（将string转换成FileJson实体属性，因需要前后端同时处理，先记录后处理）
                    billAddCollectionReq.setSaleOrderNumber(order.getOrderNumber());
                    billAddCollectionReq.setSaleOrderId(req.getOrderId());
                    List<Long> productIdList = new ArrayList<>();
                    productIdList.add(order.getScheduleId());
                    billAddCollectionReq.setProductId(productIdList);
                    billAddCollectionReq.setProductNumber(tripSchedule.getTripNumber());
                    List<String> titleList = new ArrayList<>();
                    String title = tripSchedule.getSeriesTripScheduleDataDTO().getTitle();
                    titleList.add(title);
                    billAddCollectionReq.setProductName(title);
                    billAddCollectionReq.setResourceInfo(titleList);
                    billAddCollectionReq.setSaleUserId(order.getSalesmanId());
                    billAddCollectionReq.setSaleUserName(order.getSalesmanName());
                    UserDTO userDTO = iSysUserService.queryCacheUser(order.getSalesmanId());
                    if (ObjectUtils.isNotEmpty(userDTO)) {
                        billAddCollectionReq.setSaleDeptId(userDTO.getDeptId());
                    }
                    billAddCollectionReqs.add(billAddCollectionReq);
                }
                // 新增积分抵扣收款记录
                if (StringUtils.isNotEmpty(order.getUseScore())) {
                    SeriesOrderCollection collection = new SeriesOrderCollection();
                    collection.setId(SnowflakeIdWorker.nextId());
                    collection.setOrderId(order.getId());
                    collection.setScheduleId(order.getScheduleId());
                    String collectionNumber = "SKD" + now.format(DateTimeFormatter.ofPattern(Utils.yyMMddHHmmss)) + Utils.getRandom2();
                    collection.setCollectionNumber(collectionNumber);
                    collection.setIsPos(0);
                    collection.setCollectionWay("积分抵扣");
                    collection.setGmtCreate(now);
                    collection.setPaidInAmount(new BigDecimal(Long.parseLong(order.getUseScore()) / 100));
                    collection.setPayerId(Long.parseLong(order.getMemberId()));
                    collection.setPayer(order.getMemberName());
                    collection.setIsPrint(0);
                    collection.setIsDeleted(0);
                    collection.setRemark("星赏会员积分抵扣");
                    // 新增收款记录
                    int insert = seriesOrderCollectionMapper.insert(collection);
                    if (insert <= 0) {
                        throw new BusinessException(SystemError.SYS_437);
                    }
                }
                //添加财务收款
                Result result = iFinanceBillService.addCollection(billAddCollectionReqs);
                if (result == null || result.getCode() != 0) {
                    throw new BusinessException(SystemError.SYS_437);
                }
                log.info("【旅行团支付-支付回调】, 支付成功, 财务收款完成");
                //发送短信通知
                Map<String, String> smsParam = new HashMap<>();
                smsParam.put("orderid", order.getId().toString());
                smsParam.put("code", order.getQueryNumber());
                redis.opsForValue().set(RedisConstants.TOUR_SCHEDULE_SMS + order.getId(), "1", 5, TimeUnit.MINUTES);
                sms(businessType, order.getPhoneCode(), order.getPhone(), smsParam);
            }
        }
        // 更新个人中心订单状态
        updateStatusToAppUser(order.getId());
        return Result.success(order.getId());
    }

    public void sms(Integer businessType, String phoneCode, String phone, Map<String, String> smsParam) {
        ScheduledExecutorService scheduledExecutorService = newSingleThreadScheduledExecutor();
        SmsTask smsTask = new SmsTask();
        smsTask.setRedisTemplate(redis);
        smsTask.setUserSmsService(userSmsService);
        smsTask.setScheduledExecutorService(scheduledExecutorService);
        smsTask.setBusinessType(businessType);
        smsTask.setPhoneCode(phoneCode);
        smsTask.setPhone(phone);
        smsTask.setSmsParam(smsParam);
        scheduledExecutorService.scheduleAtFixedRate(smsTask, 0, 2, TimeUnit.MINUTES);
    }

    /**
     * 支付结果
     *
     * @param orderId
     * @return
     */
    @Override
    public Result<SeriesOrderPayDTO> payResult(Long orderId) {
        SeriesOrder seriesOrder = seriesOrderMapper.selectById(orderId);
        if (seriesOrder == null) {
            return Result.failed(SystemError.TOUR_ORDER_30006);
        }
        SeriesOrderCollection seriesOrderCollection = seriesOrderCollectionMapper.selectOne(
                Wrappers.<SeriesOrderCollection>lambdaQuery()
                        .eq(SeriesOrderCollection::getOrderId, orderId)
                        .last("limit 1"));

        SeriesOrderPayDTO seriesOrderPayDTO = new SeriesOrderPayDTO();
        seriesOrderPayDTO.setTitle(seriesOrder.getTripTitle());
        seriesOrderPayDTO.setPayTime(seriesOrder.getPayTime());
        seriesOrderPayDTO.setOrderNumber(seriesOrder.getOrderNumber());
        seriesOrderPayDTO.setQueryNumber(seriesOrder.getQueryNumber());
        seriesOrderPayDTO.setPayStatus(seriesOrder.getIsPay().toString());
        if (ObjectUtils.isNotEmpty(seriesOrderCollection)) {
            seriesOrderPayDTO.setPayMethod(seriesOrderCollection.getCollectionWay());
        }
        return Result.success(seriesOrderPayDTO);
    }

    @Override
    public Result<List<MyTripOrderDTO>> recentToNow(LocalDateTime recent, LocalDateTime now) {
        List<SeriesOrder> seriesOrderList = baseMapper.selectList(Wrappers.<SeriesOrder>lambdaQuery()
                .eq(SeriesOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .ge(recent != null, SeriesOrder::getGmtModified, recent)
                .le(SeriesOrder::getGmtModified, now));

        Optional.ofNullable(seriesOrderList).orElse(new ArrayList<>(0));
        List<MyTripOrderDTO> result = new ArrayList<>();
        List<Long> orderIdList = new ArrayList<>();
        for (SeriesOrder seriesOrder : seriesOrderList) {
            MyTripOrderDTO myTripOrderDTO = EntityUtil.copy(seriesOrder, MyTripOrderDTO.class);
            myTripOrderDTO.setPayExpireDateTime(seriesOrder.getPayEndTime());
            orderIdList.add(seriesOrder.getId());
            result.add(myTripOrderDTO);
        }
        if (CollectionUtils.isNotEmpty(result)) {
            Map<Long, List<SeriesOrderTouristInfo>> map = new HashMap<>();
            Map<Long, String> touristInfoMap = new HashMap<>();
            // 查询旅客类型和人数
            List<SeriesOrderTouristInfo> seriesOrderTouristInfos = seriesOrderTouristInfoMapper.selectList(Wrappers.<SeriesOrderTouristInfo>lambdaQuery()
                    .in(SeriesOrderTouristInfo::getOrderId, orderIdList)
                    .eq(SeriesOrderTouristInfo::getIsDeleted, IsDeletedCode.NO.getCode()));
            for (SeriesOrderTouristInfo seriesOrderTouristInfo : seriesOrderTouristInfos) {
                Long orderId = seriesOrderTouristInfo.getOrderId();
                List<SeriesOrderTouristInfo> seriesOrderTouristInfos1 = map.get(seriesOrderTouristInfo.getOrderId());
                if (seriesOrderTouristInfos1 == null) {
                    List<SeriesOrderTouristInfo> list = new ArrayList<>();
                    list.add(seriesOrderTouristInfo);
                    map.put(orderId, list);
                } else {
                    seriesOrderTouristInfos1.add(seriesOrderTouristInfo);
                    map.put(orderId, seriesOrderTouristInfos1);
                }
            }

            for (Map.Entry<Long, List<SeriesOrderTouristInfo>> longListEntry : map.entrySet()) {

                List<SeriesOrderTouristInfo> value = longListEntry.getValue();
                Map<String, Long> collect = Optional.ofNullable(value).orElse(new ArrayList<>()).stream()
                        .filter(item -> StringUtils.isNotBlank(item.getTouristTypeName()))
                        .collect(Collectors.groupingBy(SeriesOrderTouristInfo::getTouristTypeName, Collectors.counting()));
                StringJoiner sj = new StringJoiner("");
                for (Map.Entry<String, Long> entry : collect.entrySet()) {
                    String info = entry.getValue() + entry.getKey();
                    sj.add(info);
                }
                touristInfoMap.put(longListEntry.getKey(), sj.toString());
            }
            for (MyTripOrderDTO myTripOrderDTO : result) {
                myTripOrderDTO.setTouristInfo(touristInfoMap.get(myTripOrderDTO.getId()));
            }

        }

        return Result.success(result);
    }

    @Override
    public List<SeriesOrderDTO> queryOrderDTOList(LocalDateTime recent, LocalDateTime now) {
        return EntityUtil.copyList(baseMapper.selectList(Wrappers.<SeriesOrder>lambdaQuery()
                .eq(SeriesOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .ge(SeriesOrder::getGmtCreate, recent)
                .le(SeriesOrder::getGmtCreate, now)), SeriesOrderDTO.class);
    }

    public MyTripOrderDTO buildEsOrderDTO(Long orderId) {
        MyTripOrderDTO orderDTO = baseMapper.selectById(MyTripOrderDTO.class, orderId);
        // 查询旅客类型和人数
        List<SeriesOrderTouristInfo> seriesOrderTouristInfos = seriesOrderTouristInfoMapper.selectList(Wrappers.<SeriesOrderTouristInfo>lambdaQuery()
                .eq(SeriesOrderTouristInfo::getOrderId, orderId)
                .eq(SeriesOrderTouristInfo::getIsDeleted, IsDeletedCode.NO.getCode()));

        Map<String, Long> collect = Optional.ofNullable(seriesOrderTouristInfos).orElse(new ArrayList<>()).stream()
                .filter(item -> StringUtils.isNotBlank(item.getTouristTypeName()))
                .collect(Collectors.groupingBy(SeriesOrderTouristInfo::getTouristTypeName, Collectors.counting()));
        StringJoiner sj = new StringJoiner("");
        for (Map.Entry<String, Long> entry : collect.entrySet()) {
            String info = entry.getValue() + entry.getKey();
            sj.add(info);
        }
        orderDTO.setTouristInfo(sj.toString());

        return orderDTO;
    }

    @Override
    public List<SeriesOrderDTO> selectList(List<Long> ids) {
        return baseMapper.selectTripScheduleSaleCount(ids, LocalDate.now());
    }

    /**
     * APP端-旅游团-订单详情
     *
     * @param req
     * @return
     */
    @Override
    public Result<ClientOrderDetailsDTO> info(ClientOrderInfoReq req) {
        PCClientOrderDetailsDTO data = infoToPc(req).getData();
        ClientOrderDetailsDTO dto = EntityUtil.copy(data, ClientOrderDetailsDTO.class);

        List<TouristInfoToPcDTO> touristInfoToPcList = data.getTouristInfoList();
        Set<String> touristTypes = touristInfoToPcList.stream()
                .map(item -> item.getTouristTypeName().substring(0, item.getTouristTypeName().length() - 1))
                .collect(Collectors.toSet());

        // 旅客信息封装
        List<TouristInfoListDTO> touristInfoList = new ArrayList<>();
        for (String touristType : touristTypes) {
            List<TouristInfoToPcDTO> currentTouristTypes = touristInfoToPcList.stream()
                    .filter(item -> item.getTouristTypeName().contains(touristType))
                    .collect(Collectors.toList());

            TouristInfoListDTO touristInfoListDTO = new TouristInfoListDTO();
            List<ClientTouristInfoDTO> touristInfoDTOS = new ArrayList<>();
            touristInfoListDTO.setTouristTypeName(touristType);
            for (TouristInfoToPcDTO currentTouristType : currentTouristTypes) {
                ClientTouristInfoDTO clientTouristInfoDTO = EntityUtil.copy(currentTouristType, ClientTouristInfoDTO.class);
                // 签证信息
                List<TouristCertificateListDTO> certificateTypeList = currentTouristType.getCertificateTypeList();
                if (CollectionUtil.isNotEmpty(certificateTypeList)) {
                    TouristCertificateListDTO touristCertificateListDTO = certificateTypeList.get(0);
                    clientTouristInfoDTO.setCertificateType1(touristCertificateListDTO.getCertificateType());
                    clientTouristInfoDTO.setCertificateNumber1(touristCertificateListDTO.getCertificateNumber());
                }
                touristInfoDTOS.add(clientTouristInfoDTO);
            }
            touristInfoListDTO.setTouristInfoDTOS(touristInfoDTOS);
            touristInfoList.add(touristInfoListDTO);
        }
        return Result.success(dto);
    }

    /**
     * PC端-旅行团订单详情
     *
     * @param req
     * @return
     */
    @Override
    public Result<PCClientOrderDetailsDTO> infoToPc(ClientOrderInfoReq req) {
        SeriesOrder order = getById(req.getOrderId());
        if (order == null || Objects.equals(order.getIsDeleted(), IsDeletedCode.YES.getCode())) {
            throw new BusinessException(SystemError.CUSTOM_ORDER_4008);
        }
        PCClientOrderDetailsDTO pcInfo = EntityUtil.copy(order, PCClientOrderDetailsDTO.class);
        // 获取封面图
        Trip trip = seriesTripService.queryTripById(order.getTripId());
        if (ObjectUtils.isNotEmpty(trip)) {
            pcInfo.setCover(trip.getCoverPhotoUrl());
        }

        // 设置订单状态
        Integer orderStatus = null;
        if (ObjectUtils.isNotEmpty(order.getIsPay())) {
            orderStatus = IsPayStatusCode.getNewStatusCode(order.getIsPay());
        }
        if (ObjectUtils.isNotEmpty(order.getOrderStatus()) && ObjectUtils.isEmpty(orderStatus)) {
            orderStatus = TourOrderStatusCode.getNewStatusCode(order.getOrderStatus());
        }
        if (order.getRefundStatus().intValue() != 0) {
            orderStatus = TourRefundStatusCode.getNewStatusCode(order.getRefundStatus());
        }

        pcInfo.setOrderStatus(orderStatus);

        // 旅客统计
        List<TouristCountDTO> touristCountList = seriesOrderTouristInfoMapper.countByOrder(order.getId());
        pcInfo.setTouristCountList(touristCountList);
        // 旅客信息
        List<SeriesOrderTouristInfoDTO> touristInfoList = seriesOrderTouristInfoMapper.queryListByOrder(order.getId(), IsDeletedCode.NO.getCode());
        Set<Long> touristIds = touristInfoList.stream().map(item -> item.getMainDataId()).collect(Collectors.toSet());
        List<TouristInfoToPcDTO> pcInfoList = new ArrayList<>();
        for (Long touristId : touristIds) {
            List<SeriesOrderTouristInfoDTO> touristInfos = touristInfoList.stream()
                    .filter(item -> item.getMainDataId().equals(touristId))
                    .collect(Collectors.toList());
            for (int i = 0; i < touristInfos.size(); i++) {
                SeriesOrderTouristInfoDTO seriesOrderTouristInfoDTO = touristInfos.get(i);
                TouristInfoToPcDTO copy = EntityUtil.copy(seriesOrderTouristInfoDTO, TouristInfoToPcDTO.class);
                copy.setTouristTypeName(seriesOrderTouristInfoDTO.getTouristTypeName() + (i + 1));
                List<TouristCertificateListDTO> certificateTypeList = new ArrayList<>();
                if (ObjectUtils.isNotEmpty(seriesOrderTouristInfoDTO.getCertificateType1())) {
                    TouristCertificateListDTO touristCertificateListDTO = new TouristCertificateListDTO();
                    touristCertificateListDTO.setCertificateType(seriesOrderTouristInfoDTO.getCertificateType1());
                    touristCertificateListDTO.setCertificateNumber(seriesOrderTouristInfoDTO.getCertificateNumber1());
                    certificateTypeList.add(touristCertificateListDTO);
                }
                if (ObjectUtils.isNotEmpty(seriesOrderTouristInfoDTO.getCertificateType2())) {
                    TouristCertificateListDTO touristCertificateListDTO = new TouristCertificateListDTO();
                    touristCertificateListDTO.setCertificateType(seriesOrderTouristInfoDTO.getCertificateType2());
                    touristCertificateListDTO.setCertificateNumber(seriesOrderTouristInfoDTO.getCertificateNumber2());
                    certificateTypeList.add(touristCertificateListDTO);
                }
                if (ObjectUtils.isNotEmpty(seriesOrderTouristInfoDTO.getCertificateType3())) {
                    TouristCertificateListDTO touristCertificateListDTO = new TouristCertificateListDTO();
                    touristCertificateListDTO.setCertificateType(seriesOrderTouristInfoDTO.getCertificateType3());
                    touristCertificateListDTO.setCertificateNumber(seriesOrderTouristInfoDTO.getCertificateNumber3());
                    certificateTypeList.add(touristCertificateListDTO);
                }
                copy.setCertificateTypeList(certificateTypeList);
                pcInfoList.add(copy);
            }
        }
        pcInfo.setTouristInfoList(pcInfoList);

        // 金额
        QueryWrapper<SeriesOrderAmountStatistics> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", order.getId());
        SeriesOrderAmountStatistics statistics = seriesOrderAmountStatisticsMapper.selectOne(queryWrapper);
        if (statistics != null) {
            pcInfo.setTotalReceivables(statistics.getTotalReceivables());
            pcInfo.setTotalTourFee(statistics.getTotalTourFee());
            pcInfo.setCollectionFee(statistics.getCollectionFee());
            pcInfo.setOtherAmount(statistics.getOtherAmount());
            pcInfo.setAdjustmentCost(statistics.getAdjustmentCost());
        }

        // 预订须知
        SeriesTripScheduleDTO tripSchedule = iSeriesTripScheduleService.getTripScheduleId(order.getScheduleId());
        if (tripSchedule != null && tripSchedule.getSeriesTripScheduleDataDTO() != null) {
            pcInfo.setSignNotice(tripSchedule.getSeriesTripScheduleDataDTO().getSignNotice());
        }
        //

        // 联系人电话
        String contactTelephones = pcInfo.getContactTelephones();
        TelephonesJson telephonesJson = null;
        try {
            telephonesJson = JSON.parseObject(contactTelephones, TelephonesJson.class);
        } catch (Exception e) {
            List<TelephonesJson> telephonesJsons = JSONArray.parseArray(contactTelephones, TelephonesJson.class);
            if (CollectionUtil.isNotEmpty(telephonesJsons)) {
                telephonesJson = telephonesJsons.get(0);
            }
        }
        if (ObjectUtils.isNotEmpty(telephonesJson)) {
            String areaCode = telephonesJson.getAreaCode();
            if (areaCode.indexOf("+") != -1) {
                areaCode = areaCode.substring(1);
            }
            String phone = areaCode + "-" + telephonesJson.getPhoneNo();
            pcInfo.setContactTelephones(phone);
        }

        // 紧急联系人
        List<SeriesOrderTouristInfo> seriesOrderTouristInfos = seriesOrderTouristInfoMapper
                .selectList(Wrappers.<SeriesOrderTouristInfo>lambdaQuery()
                        .eq(SeriesOrderTouristInfo::getOrderId, req.getOrderId())
                        .eq(SeriesOrderTouristInfo::getIsDeleted, com.ctshk.common.enums.IsDeletedCode.NO.getCode())
                        .isNotNull(SeriesOrderTouristInfo::getEmergencyContactName));
        if (ObjectUtils.isNotEmpty(seriesOrderTouristInfos)) {
            SeriesOrderTouristInfo seriesOrderTouristInfo = seriesOrderTouristInfos.get(0);
            pcInfo.setEmergencyContactName(seriesOrderTouristInfo.getEmergencyContactName());
            pcInfo.setEmergencyMobile(seriesOrderTouristInfo.getEmergencyMobile());
            String emergencyMobileAreaCode = seriesOrderTouristInfo.getEmergencyMobileAreaCode();
            if (emergencyMobileAreaCode.indexOf("+") != -1) {
                emergencyMobileAreaCode = emergencyMobileAreaCode.substring(1, emergencyMobileAreaCode.length());
            }
            pcInfo.setEmergencyMobileAreaCode(emergencyMobileAreaCode);
        }
        return Result.success(pcInfo);
    }

    /**
     * 修改联络人信息
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<CustomOrderUpdateContactDTO> updateContact(CustomOrderUpdateContactReq req) {
        SeriesOrder order = getById(req.getOrderId());
        if (order == null || Objects.equals(order.getIsDeleted(), 1)) {
            throw new BusinessException(SystemError.CUSTOM_ORDER_4008);
        }
        order = EntityUtil.copy(req, SeriesOrder.class);
        order.setId(req.getOrderId());
        order.setModifiedId(req.getUserId());
        boolean update = updateById(order);
        if (!update) {
            throw new BusinessException(SystemError.SYS_437);
        }
        CustomOrderUpdateContactDTO dto = EntityUtil.copy(order, CustomOrderUpdateContactDTO.class);
        return Result.success(dto);
    }

    /**
     * 查询订单信息
     *
     * @param orderId
     * @return
     */
    @Override
    public Result<OrderInfoDTO> orderInfo(Long orderId) {
        SeriesOrder seriesOrder = seriesOrderMapper.selectOne(Wrappers.<SeriesOrder>lambdaQuery().eq(SeriesOrder::getId, orderId));
        if (ObjectUtils.isNotEmpty(seriesOrder)) {
            OrderInfoDTO orderInfo = EntityUtil.copy(seriesOrder, OrderInfoDTO.class);
            orderInfo.setBusinessType(seriesTripService.findTripBusinessTypeById(seriesOrder.getTripId()));
            orderInfo.setTotalPrice(seriesOrder.getTotalPrice());
            return Result.success(orderInfo);
        }
        return Result.failed(SystemError.TOUR_ORDER_30006);
    }

    /**
     * C端唤起支付获取订单信息
     *
     * @param id
     * @param type
     * @return
     */
    @Override
    public CallPayDTO getCallPayInfo(Long id, int type) {
        OrderPayInfoDTO infoDTO = seriesOrderMapper.queryOrderPayInfo(id);
        if (infoDTO == null) {
            throw new BusinessException(SystemError.CUSTOM_ORDER_4008);
        }
        if (infoDTO.getOrderValidTime().isBefore(LocalDateTime.now())) {
            throw new BusinessException(SystemError.CUSTOM_ORDER_4055);
        }

        CallPayDTO dto = EntityUtil.copy(infoDTO, CallPayDTO.class);
        if (type == 1) {
            dto.setBody("旅行團出境遊訂單支付");
        } else {
            dto.setBody("旅行團入境遊訂單支付");
        }
        dto.setCurrency(PayCurrency.HKD);
        return dto;
    }

    @Override
    public Result tripIsExist(TripIsExistReq req) {
        BoundHashOperations<String, String, String> hashOps = redis.boundHashOps(RedisConstants.TOUR_SCHEDULE_DETAILS + req.getChannelId() + ":");
        if (hashOps.hasKey(req.getTripId().toString())) {
            return Result.success();
        }
        return Result.failed(SystemError.TOUR_ORDER_30034);
    }

    @Override
    public Result remainCheck(RemainCheckReq req) {
        // 可销售余位验证
        Integer remain = iSeriesTripScheduleService.queryScheduleRemain(req.getId());
        if (ObjectUtils.isEmpty(remain) || remain < req.getNum()) {
            return Result.failed(SystemError.TOUR_ORDER_30029);
        }
        return Result.success();
    }

    /**
     * 退款原因
     *
     * @return
     */
    @Override
    public Result<List<RefundReasonDTO>> RefundReason() {
        List<MainDataRowFieldDataDTO> mainDataRowFieldDataDTOS = iMainDataTableService.groupByDataField(1370313078729801730L, 1370313116818276354L);
        List<RefundReasonDTO> refundReasonDTOS = new ArrayList<>();
        for (MainDataRowFieldDataDTO mainDataRowFieldDataDTO : mainDataRowFieldDataDTOS) {
            RefundReasonDTO refundReasonDTO = new RefundReasonDTO();
            refundReasonDTO.setId(mainDataRowFieldDataDTO.getId());
            refundReasonDTO.setValue(mainDataRowFieldDataDTO.getFieldValue());
            refundReasonDTOS.add(refundReasonDTO);
        }
        return Result.success(refundReasonDTOS);
    }

    /**
     * 异步发送订单数据到个人中心
     *
     * @param orderId 订单Id
     */
    public void sendOrderToAppUser(Long orderId) {
        CompletableFuture.runAsync(() -> {
            try {
                MyTripOrderDTO orderDTO = buildEsOrderDTO(orderId);
                orderEsService.saveOrderToEs(orderDTO, SystemBusinessType.OUTBOUND_TRAVEL);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 异步更新订单状态到个人中心
     */
    public void updateStatusToAppUser(Long orderId) {
        CompletableFuture.runAsync(() -> {
            try {
                SeriesOrder order = baseMapper.selectById(orderId);
                orderEsService.updateStatusToEs(order.getId(), SystemBusinessType.OUTBOUND_TRAVEL.getCode(),
                        order.getOrderStatus(), order.getIsPay(), order.getScheduleStatus(),
                        order.getRefundStatus());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    @Override
    @GlobalTransactional
    public Result notPaid(Long id) {
        SeriesOrder seriesOrder = baseMapper.selectOne(new QueryWrapper<SeriesOrder>().lambda()
                .eq(SeriesOrder::getId, id)
                .eq(SeriesOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .select(SeriesOrder::getId, SeriesOrder::getOrderNumber, SeriesOrder::getIsPay));
        if (seriesOrder == null) {
            log.error("【旅行团订单定时任务-未支付超时】找不到订单, orderNumber:{}", seriesOrder.getOrderNumber());
            throw new BusinessException(SystemError.TOUR_ORDER_30006);
        }
        log.info("【旅行团订单定时任务-未支付超时】修改订单状态, orderNumber:{}, data:{}", seriesOrder.getOrderNumber(), JSON.toJSONString(seriesOrder));
        if (Objects.equals(seriesOrder.getIsPay(), IsPayStatusCode.PENDING_PAYMENT.getOldCode())) {
            int update = baseMapper.update(null, new UpdateWrapper<SeriesOrder>().lambda()
                    .eq(SeriesOrder::getId, id)
                    .set(SeriesOrder::getOrderStatus, OrderPaymentStatus.ALREADY_CANCEL.getCode())
                    .set(SeriesOrder::getModifiedId, 1L)
                    .set(SeriesOrder::getGmtModified, LocalDateTime.now()));

            if (update <= 0) {
                throw new BusinessException(SystemError.TOUR_ORDER_30040);
            }
        }
        return Result.success();
    }

}